PLplot 5.9.6
|
00001 /* $Id$ 00002 * 00003 * Central dispatch facility for PLplot. 00004 * Also contains the PLplot main data structures, external access 00005 * routines, and initialization calls. 00006 * 00007 * This stuff used to be in "dispatch.h", "dispatch.c", and "base.c". 00008 * 00009 * 00010 * Copyright (C) 2004 Joao Cardoso 00011 * Copyright (C) 2004, 2005 Rafael Laboissiere 00012 * Copyright (C) 2004, 2006 Andrew Ross 00013 * Copyright (C) 2004 Andrew Roach 00014 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Alan W. Irwin 00015 * Copyright (C) 2005 Thomas J. Duck 00016 * 00017 * This file is part of PLplot. 00018 * 00019 * PLplot is free software; you can redistribute it and/or modify 00020 * it under the terms of the GNU General Library Public License as published 00021 * by the Free Software Foundation; either version 2 of the License, or 00022 * (at your option) any later version. 00023 * 00024 * PLplot is distributed in the hope that it will be useful, 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00027 * GNU Library General Public License for more details. 00028 * 00029 * You should have received a copy of the GNU Library General Public License 00030 * along with PLplot; if not, write to the Free Software 00031 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00032 * 00033 */ 00034 00035 #define DEBUG 00036 #define NEED_PLDEBUG 00037 #include "plcore.h" 00038 00039 #ifdef ENABLE_DYNDRIVERS 00040 #ifndef LTDL_WIN32 00041 #include <ltdl.h> 00042 #else 00043 #include "ltdl_win32.h" 00044 #endif 00045 #endif 00046 00047 #if HAVE_DIRENT_H 00048 /* The following conditional is a workaround for a bug in the MacOSX system. 00049 * When the dirent.h file will be fixed upstream by Apple Inc, this should 00050 * go away. */ 00051 # ifdef NEED_SYS_TYPE_H 00052 # include <sys/types.h> 00053 # endif 00054 # include <dirent.h> 00055 # define NAMLEN( dirent ) strlen( ( dirent )->d_name ) 00056 #else 00057 # if defined ( _MSC_VER ) 00058 # include "dirent_msvc.h" 00059 # else 00060 # define dirent direct 00061 # define NAMLEN( dirent ) ( dirent )->d_namlen 00062 # if HAVE_SYS_NDIR_H 00063 # include <sys/ndir.h> 00064 # endif 00065 # if HAVE_SYS_DIR_H 00066 # include <sys/dir.h> 00067 # endif 00068 # if HAVE_NDIR_H 00069 # include <ndir.h> 00070 # endif 00071 # endif 00072 #endif 00073 00074 /* AM: getcwd has a somewhat strange status on Windows, its proper 00075 * name is _getcwd, this is a problem in the case of DLLs, like with 00076 * the Java bindings. The functions _getcwd() and chdir() are 00077 * declared in direct.h for Visual C++. Since chdir() is deprecated 00078 * (but still available) in Visual C++ we redefine chdir to _chdir. 00079 */ 00080 #if defined ( _MSC_VER ) 00081 # include <direct.h> 00082 # define getcwd _getcwd 00083 # define chdir _chdir 00084 #endif 00085 00086 #define BUFFER_SIZE 80 00087 #define BUFFER2_SIZE 300 00088 #define DRVSPEC_SIZE 400 00089 00090 #include <errno.h> 00091 00092 /*--------------------------------------------------------------------------*\ 00093 * Driver Interface 00094 * 00095 * These routines are the low-level interface to the driver -- all calls to 00096 * driver functions must pass through here. For implementing driver- 00097 * specific functions, the escape function is provided. The command stream 00098 * gets duplicated to the plot buffer here. 00099 * 00100 * All functions that result in graphics actually being plotted (rather than 00101 * just a change of state) are filtered as necessary before being passed on. 00102 * The default settings do not require any filtering, i.e. PLplot physical 00103 * coordinates are the same as the device physical coordinates (currently 00104 * this can't be changed anyway), and a global view equal to the entire page 00105 * is used. 00106 * 00107 * The reason one wants to put view-specific filtering here is that if 00108 * enabled, the plot buffer should receive the unfiltered data stream. This 00109 * allows a specific view to be used from an interactive device (e.g. TCL/TK 00110 * driver) but be restored to the full view at any time merely by 00111 * reprocessing the contents of the plot buffer. 00112 * 00113 * The metafile, on the other hand, *should* be affected by changes in the 00114 * view, since this is a crucial editing capability. It is recommended that 00115 * the initial metafile be created without a restricted global view, and 00116 * modification of the view done on a per-plot basis as desired during 00117 * subsequent processing. 00118 * 00119 \*--------------------------------------------------------------------------*/ 00120 00121 enum { AT_BOP, DRAWING, AT_EOP }; 00122 00123 /* Initialize device. */ 00124 /* The plot buffer must be called last. */ 00125 00126 /* The following array of chars is used both here and in plsym.c for 00127 * translating the Greek characters from the #g escape sequences into 00128 * the Hershey and Unicode codings 00129 */ 00130 const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw"; 00131 00132 void 00133 plP_init( void ) 00134 { 00135 char * save_locale; 00136 plsc->page_status = AT_EOP; 00137 plsc->stream_closed = FALSE; 00138 00139 save_locale = plsave_set_locale(); 00140 ( *plsc->dispatch_table->pl_init )( (struct PLStream_struct *) plsc ); 00141 plrestore_locale( save_locale ); 00142 00143 if ( plsc->plbuf_write ) 00144 plbuf_init( plsc ); 00145 } 00146 00147 /* End of page */ 00148 /* The plot buffer must be called first. */ 00149 /* Ignore instruction if already at eop. */ 00150 00151 void 00152 plP_eop( void ) 00153 { 00154 int skip_driver_eop = 0; 00155 00156 if ( plsc->page_status == AT_EOP ) 00157 return; 00158 00159 plsc->page_status = AT_EOP; 00160 00161 if ( plsc->plbuf_write ) 00162 plbuf_eop( plsc ); 00163 00164 /* Call user eop handler if present. */ 00165 00166 if ( plsc->eop_handler != NULL ) 00167 ( *plsc->eop_handler )( plsc->eop_data, &skip_driver_eop ); 00168 00169 if ( !skip_driver_eop ) 00170 { 00171 char *save_locale = plsave_set_locale(); 00172 if ( !plsc->stream_closed ) 00173 { 00174 ( *plsc->dispatch_table->pl_eop )( (struct PLStream_struct *) plsc ); 00175 } 00176 plrestore_locale( save_locale ); 00177 } 00178 } 00179 00180 /* Set up new page. */ 00181 /* The plot buffer must be called last. */ 00182 /* Ignore if already at bop. */ 00183 /* It's not actually necessary to be AT_EOP here, so don't check for it. */ 00184 00185 void 00186 plP_bop( void ) 00187 { 00188 int skip_driver_bop = 0; 00189 00190 plP_subpInit(); 00191 if ( plsc->page_status == AT_BOP ) 00192 return; 00193 00194 plsc->page_status = AT_BOP; 00195 plsc->nplwin = 0; 00196 00197 /* Call user bop handler if present. */ 00198 00199 if ( plsc->bop_handler != NULL ) 00200 ( *plsc->bop_handler )( plsc->bop_data, &skip_driver_bop ); 00201 00202 if ( !skip_driver_bop ) 00203 { 00204 char *save_locale = plsave_set_locale(); 00205 if ( !plsc->stream_closed ) 00206 { 00207 ( *plsc->dispatch_table->pl_bop )( (struct PLStream_struct *) plsc ); 00208 } 00209 plrestore_locale( save_locale ); 00210 } 00211 00212 if ( plsc->plbuf_write ) 00213 plbuf_bop( plsc ); 00214 } 00215 00216 /* Tidy up device (flush buffers, close file, etc). */ 00217 00218 void 00219 plP_tidy( void ) 00220 { 00221 char * save_locale; 00222 if ( plsc->tidy ) 00223 { 00224 ( *plsc->tidy )( plsc->tidy_data ); 00225 plsc->tidy = NULL; 00226 plsc->tidy_data = NULL; 00227 } 00228 00229 save_locale = plsave_set_locale(); 00230 if ( !plsc->stream_closed ) 00231 { 00232 ( *plsc->dispatch_table->pl_tidy )( (struct PLStream_struct *) plsc ); 00233 } 00234 plrestore_locale( save_locale ); 00235 00236 if ( plsc->plbuf_write ) 00237 { 00238 plbuf_tidy( plsc ); 00239 } 00240 00241 plsc->OutFile = NULL; 00242 } 00243 00244 /* Change state. */ 00245 00246 void 00247 plP_state( PLINT op ) 00248 { 00249 char * save_locale; 00250 if ( plsc->plbuf_write ) 00251 plbuf_state( plsc, op ); 00252 00253 save_locale = plsave_set_locale(); 00254 if ( !plsc->stream_closed ) 00255 { 00256 ( *plsc->dispatch_table->pl_state )( (struct PLStream_struct *) plsc, op ); 00257 } 00258 plrestore_locale( save_locale ); 00259 } 00260 00261 /* Escape function, for driver-specific commands. */ 00262 00263 void 00264 plP_esc( PLINT op, void *ptr ) 00265 { 00266 char * save_locale; 00267 PLINT clpxmi, clpxma, clpymi, clpyma; 00268 EscText* args; 00269 00270 /* The plot buffer must be called first */ 00271 if ( plsc->plbuf_write ) 00272 plbuf_esc( plsc, op, ptr ); 00273 00274 /* Text coordinates must pass through the driver interface filter */ 00275 if ( ( op == PLESC_HAS_TEXT && plsc->dev_unicode ) || 00276 ( op == PLESC_END_TEXT && plsc->alt_unicode ) ) 00277 { 00278 /* Apply the driver interface filter */ 00279 if ( plsc->difilt ) 00280 { 00281 args = (EscText*) ptr; 00282 difilt( &( args->x ), &( args->y ), 1, &clpxmi, &clpxma, &clpymi, &clpyma ); 00283 } 00284 } 00285 00286 save_locale = plsave_set_locale(); 00287 if ( !plsc->stream_closed ) 00288 { 00289 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, op, ptr ); 00290 } 00291 plrestore_locale( save_locale ); 00292 } 00293 00294 /* Set up plot window parameters. */ 00295 /* The plot buffer must be called first */ 00296 /* Some drivers (metafile, Tk) need access to this data */ 00297 00298 void 00299 plP_swin( PLWindow *plwin ) 00300 { 00301 PLWindow *w; 00302 PLINT clpxmi, clpxma, clpymi, clpyma; 00303 00304 /* Provide plot buffer with unfiltered window data */ 00305 00306 if ( plsc->plbuf_write ) 00307 plbuf_esc( plsc, PLESC_SWIN, (void *) plwin ); 00308 00309 w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS]; 00310 00311 w->dxmi = plwin->dxmi; 00312 w->dxma = plwin->dxma; 00313 w->dymi = plwin->dymi; 00314 w->dyma = plwin->dyma; 00315 00316 if ( plsc->difilt ) 00317 { 00318 xscl[0] = plP_dcpcx( w->dxmi ); 00319 xscl[1] = plP_dcpcx( w->dxma ); 00320 yscl[0] = plP_dcpcy( w->dymi ); 00321 yscl[1] = plP_dcpcy( w->dyma ); 00322 00323 difilt( xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma ); 00324 00325 w->dxmi = plP_pcdcx( xscl[0] ); 00326 w->dxma = plP_pcdcx( xscl[1] ); 00327 w->dymi = plP_pcdcy( yscl[0] ); 00328 w->dyma = plP_pcdcy( yscl[1] ); 00329 } 00330 00331 w->wxmi = plwin->wxmi; 00332 w->wxma = plwin->wxma; 00333 w->wymi = plwin->wymi; 00334 w->wyma = plwin->wyma; 00335 00336 /* If the driver wants to process swin commands, call it now */ 00337 /* It must use the filtered data, which it can get from *plsc */ 00338 00339 if ( plsc->dev_swin ) 00340 { 00341 char *save_locale = plsave_set_locale(); 00342 if ( !plsc->stream_closed ) 00343 { 00344 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 00345 PLESC_SWIN, NULL ); 00346 } 00347 plrestore_locale( save_locale ); 00348 } 00349 } 00350 00351 /*--------------------------------------------------------------------------*\ 00352 * Drawing commands. 00353 \*--------------------------------------------------------------------------*/ 00354 00355 /* Draw line between two points */ 00356 /* The plot buffer must be called first so it gets the unfiltered data */ 00357 00358 void 00359 plP_line( short *x, short *y ) 00360 { 00361 PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma; 00362 00363 plsc->page_status = DRAWING; 00364 00365 if ( plsc->plbuf_write ) 00366 plbuf_line( plsc, x[0], y[0], x[1], y[1] ); 00367 00368 if ( plsc->difilt ) 00369 { 00370 for ( i = 0; i < npts; i++ ) 00371 { 00372 xscl[i] = x[i]; 00373 yscl[i] = y[i]; 00374 } 00375 difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma ); 00376 plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline ); 00377 } 00378 else 00379 { 00380 grline( x, y, npts ); 00381 } 00382 } 00383 00384 /* Draw polyline */ 00385 /* The plot buffer must be called first */ 00386 00387 void 00388 plP_polyline( short *x, short *y, PLINT npts ) 00389 { 00390 PLINT i, clpxmi, clpxma, clpymi, clpyma; 00391 00392 plsc->page_status = DRAWING; 00393 00394 if ( plsc->plbuf_write ) 00395 plbuf_polyline( plsc, x, y, npts ); 00396 00397 if ( plsc->difilt ) 00398 { 00399 for ( i = 0; i < npts; i++ ) 00400 { 00401 xscl[i] = x[i]; 00402 yscl[i] = y[i]; 00403 } 00404 difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma ); 00405 plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, 00406 grpolyline ); 00407 } 00408 else 00409 { 00410 grpolyline( x, y, npts ); 00411 } 00412 } 00413 00414 /* Fill polygon */ 00415 /* The plot buffer must be called first */ 00416 /* Here if the desired area fill capability isn't present, we mock up */ 00417 /* something in software */ 00418 00419 static int foo; 00420 00421 void 00422 plP_fill( short *x, short *y, PLINT npts ) 00423 { 00424 PLINT i, clpxmi, clpxma, clpymi, clpyma; 00425 00426 plsc->page_status = DRAWING; 00427 00428 if ( plsc->plbuf_write ) 00429 { 00430 plsc->dev_npts = npts; 00431 plsc->dev_x = x; 00432 plsc->dev_y = y; 00433 plbuf_esc( plsc, PLESC_FILL, NULL ); 00434 } 00435 00436 /* Account for driver ability to do fills */ 00437 00438 if ( plsc->patt == 0 && !plsc->dev_fill0 ) 00439 { 00440 if ( !foo ) 00441 { 00442 plwarn( "Driver does not support hardware solid fills, switching to software fill.\n" ); 00443 foo = 1; 00444 } 00445 plsc->patt = 8; 00446 plpsty( plsc->patt ); 00447 } 00448 if ( plsc->dev_fill1 ) 00449 { 00450 plsc->patt = -ABS( plsc->patt ); 00451 } 00452 00453 /* Perform fill. Here we MUST NOT allow the software fill to pass through the 00454 * driver interface filtering twice, else we get the infamous 2*rotation for 00455 * software fills on orientation swaps. 00456 */ 00457 00458 if ( plsc->patt > 0 ) 00459 plfill_soft( x, y, npts ); 00460 00461 else 00462 { 00463 if ( plsc->difilt ) 00464 { 00465 for ( i = 0; i < npts; i++ ) 00466 { 00467 xscl[i] = x[i]; 00468 yscl[i] = y[i]; 00469 } 00470 difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma ); 00471 plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, 00472 grfill ); 00473 } 00474 else 00475 { 00476 grfill( x, y, npts ); 00477 } 00478 } 00479 } 00480 00481 /* Render a gradient */ 00482 /* The plot buffer must be called first */ 00483 /* N.B. plP_gradient is never called (see plgradient) unless the 00484 * device driver has set plsc->dev_gradient to true. */ 00485 00486 void 00487 plP_gradient( short *x, short *y, PLINT npts ) 00488 { 00489 PLINT i, clpxmi, clpxma, clpymi, clpyma; 00490 00491 plsc->page_status = DRAWING; 00492 00493 if ( plsc->plbuf_write ) 00494 { 00495 plsc->dev_npts = npts; 00496 plsc->dev_x = x; 00497 plsc->dev_y = y; 00498 plbuf_esc( plsc, PLESC_GRADIENT, NULL ); 00499 } 00500 00501 /* Render gradient with driver. */ 00502 if ( plsc->difilt ) 00503 { 00504 for ( i = 0; i < npts; i++ ) 00505 { 00506 xscl[i] = x[i]; 00507 yscl[i] = y[i]; 00508 } 00509 difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma ); 00510 plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, 00511 grgradient ); 00512 } 00513 else 00514 { 00515 grgradient( x, y, npts ); 00516 } 00517 } 00518 00519 /* Account for driver ability to draw text itself */ 00520 /* 00521 #define DEBUG_TEXT 00522 */ 00523 00524 /*--------------------------------------------------------------------------*\ 00525 * int text2num( char *text, char end, PLUNICODE *num) 00526 * char *text - pointer to the text to be parsed 00527 * char end - end character (i.e. ')' or ']' to stop parsing 00528 * PLUNICODE *num - pointer to an PLUNICODE to store the value 00529 * 00530 * Function takes a string, which can be either hex or decimal, 00531 * and converts it into an PLUNICODE, stopping at either a null, 00532 * or the character pointed to by 'end'. This implementation using 00533 * the C library strtoul replaces the original brain-dead version 00534 * and should be more robust to invalid control strings. 00535 \*--------------------------------------------------------------------------*/ 00536 00537 int text2num( const char *text, char end, PLUNICODE *num ) 00538 { 00539 char *endptr; 00540 char msgbuf[BUFFER_SIZE]; 00541 00542 *num = strtoul( text, &endptr, 0 ); 00543 00544 if ( end != endptr[0] ) 00545 { 00546 snprintf( msgbuf, BUFFER_SIZE, "text2num: invalid control string detected - %c expected", end ); 00547 plwarn( msgbuf ); 00548 } 00549 00550 return (int) ( endptr - text ); 00551 } 00552 00553 /*--------------------------------------------------------------------------*\ 00554 * int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower) 00555 * char *text - pointer to the text to be parsed 00556 * unsigned char *hexdigit - pointer to hex value that is stored. 00557 * unsigned char *hexpower - pointer to hex power (left shift) that is stored. 00558 * 00559 * Function takes a pointer to a string, which is looked up in a table 00560 * to determine the corresponding FCI (font characterization integer) 00561 * hex digit value and hex power (left shift). All matched strings 00562 * start with "<" and end with the two characters "/>". 00563 * If the lookup succeeds, hexdigit and hexpower are set to the appropriate 00564 * values in the table, and the function returns the number of characters 00565 * in text that are consumed by the matching string in the table lookup. 00566 * 00567 * If the lookup fails, hexdigit is set to 0, hexpower is set to and 00568 * impossible value, and the function returns 0. 00569 \*--------------------------------------------------------------------------*/ 00570 00571 int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower ) 00572 { 00573 typedef struct 00574 { 00575 char *ptext; 00576 unsigned char hexdigit; 00577 unsigned char hexpower; 00578 } 00579 TextLookupTable; 00580 /* This defines the various font control commands and the corresponding 00581 * hexdigit and hexpower in the FCI. 00582 */ 00583 #define N_TextLookupTable 10 00584 const TextLookupTable lookup[N_TextLookupTable] = { 00585 { "<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY }, 00586 { "<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY }, 00587 { "<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY }, 00588 { "<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY }, 00589 { "<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY }, 00590 { "<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE }, 00591 { "<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE }, 00592 { "<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE }, 00593 { "<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT }, 00594 { "<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT } 00595 }; 00596 int i, length; 00597 for ( i = 0; i < N_TextLookupTable; i++ ) 00598 { 00599 length = strlen( lookup[i].ptext ); 00600 if ( !strncmp( text, lookup[i].ptext, length ) ) 00601 { 00602 *hexdigit = lookup[i].hexdigit; 00603 *hexpower = lookup[i].hexpower; 00604 return ( length ); 00605 } 00606 } 00607 *hexdigit = 0; 00608 *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE; 00609 return ( 0 ); 00610 } 00611 00612 static PLUNICODE unicode_buffer[1024]; 00613 00614 void 00615 plP_text( PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y, 00616 PLINT refx, PLINT refy, const char *string ) 00617 { 00618 if ( plsc->dev_text ) /* Does the device render it's own text ? */ 00619 { 00620 EscText args; 00621 short len = 0; 00622 char skip; 00623 unsigned short i, j; 00624 PLUNICODE code; 00625 char esc; 00626 int idx; 00627 00628 args.base = base; 00629 args.just = just; 00630 args.xform = xform; 00631 args.x = x; 00632 args.y = y; 00633 args.refx = refx; 00634 args.refy = refy; 00635 args.string = string; 00636 00637 if ( plsc->dev_unicode ) /* Does the device also understand unicode? */ 00638 { 00639 PLINT ig; 00640 PLUNICODE fci; 00641 unsigned char hexdigit, hexpower; 00642 00643 /* Now process the text string */ 00644 00645 if ( string != NULL ) /* If the string isn't blank, then we will 00646 * continue 00647 */ 00648 00649 { 00650 len = strlen( string ); /* this length is only used in the loop 00651 * counter, we will work out the length of 00652 * the unicode string as we go */ 00653 plgesc( &esc ); 00654 00655 /* At this stage we will do some translations into unicode, like 00656 * conversion to Greek , and will save other translations such as 00657 * superscript for the driver to do later on. As we move through 00658 * the string and do the translations, we will get 00659 * rid of the esc character sequence, just replacing it with 00660 * unicode. 00661 */ 00662 00663 /* Obtain FCI (font characterization integer) for start of 00664 * string. */ 00665 plgfci( &fci ); 00666 00667 /* Walk through the string, and convert 00668 * some stuff to unicode on the fly */ 00669 for ( j = i = 0; i < len; i++ ) 00670 { 00671 skip = 0; 00672 00673 if ( string[i] == esc ) 00674 { 00675 switch ( string[i + 1] ) 00676 { 00677 case '(': /* hershey code */ 00678 i += 2 + text2num( &string[i + 2], ')', &code ); 00679 idx = plhershey2unicode( code ); 00680 unicode_buffer[j++] = \ 00681 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode; 00682 00683 00684 /* if unicode_buffer[j-1] corresponds to the escape 00685 * character must unescape it by appending one more. 00686 * This will probably always be necessary since it is 00687 * likely unicode_buffer will always have to contain 00688 * escape characters that are interpreted by the device 00689 * driver. 00690 */ 00691 if ( unicode_buffer[j - 1] == esc ) 00692 unicode_buffer[j++] = esc; 00693 j--; 00694 skip = 1; 00695 break; 00696 00697 case '[': /* unicode */ 00698 i += 2 + text2num( &string[i + 2], ']', &code ); 00699 unicode_buffer[j++] = code; 00700 00701 00702 /* if unicode_buffer[j-1] corresponds to the escape 00703 * character must unescape it by appending one more. 00704 * This will probably always be necessary since it is 00705 * likely unicode_buffer will always have to contain 00706 * escape characters that are interpreted by the device 00707 * driver. 00708 */ 00709 if ( unicode_buffer[j - 1] == esc ) 00710 unicode_buffer[j++] = esc; 00711 j--; 00712 skip = 1; 00713 break; 00714 00715 case '<': /* change font*/ 00716 if ( '0' <= string[i + 2] && string[i + 2] <= '9' ) 00717 { 00718 i += 2 + text2num( &string[i + 2], '>', &code ); 00719 if ( code & PL_FCI_MARK ) 00720 { 00721 /* code is a complete FCI (font characterization 00722 * integer): change FCI to this value. 00723 */ 00724 fci = code; 00725 unicode_buffer[j] = fci; 00726 skip = 1; 00727 } 00728 else 00729 { 00730 /* code is not complete FCI. Change 00731 * FCI with hex power in rightmost hex 00732 * digit and hex digit value in second rightmost 00733 * hex digit. 00734 */ 00735 hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK; 00736 hexpower = code & PL_FCI_HEXPOWER_MASK; 00737 plP_hex2fci( hexdigit, hexpower, &fci ); 00738 unicode_buffer[j] = fci; 00739 skip = 1; 00740 } 00741 } 00742 else 00743 { 00744 i += text2fci( &string[i + 1], &hexdigit, &hexpower ); 00745 if ( hexpower < 7 ) 00746 { 00747 plP_hex2fci( hexdigit, hexpower, &fci ); 00748 unicode_buffer[j] = fci; 00749 skip = 1; 00750 } 00751 } 00752 break; 00753 00754 case 'f': /* Deprecated Hershey-style font change*/ 00755 case 'F': /* Deprecated Hershey-style font change*/ 00756 /* We implement an approximate response here so that 00757 * reasonable results are obtained for unicode fonts, 00758 * but this method is deprecated and the #<nnn> or 00759 * #<command string> methods should be used instead 00760 * to change unicode fonts in mid-string. 00761 */ 00762 fci = PL_FCI_MARK; 00763 if ( string[i + 2] == 'n' ) 00764 { 00765 /* medium, upright, sans-serif */ 00766 plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci ); 00767 } 00768 else if ( string[i + 2] == 'r' ) 00769 { 00770 /* medium, upright, serif */ 00771 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci ); 00772 } 00773 else if ( string[i + 2] == 'i' ) 00774 { 00775 /* medium, italic, serif */ 00776 plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci ); 00777 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci ); 00778 } 00779 else if ( string[i + 2] == 's' ) 00780 { 00781 /* medium, upright, script */ 00782 plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci ); 00783 } 00784 else 00785 fci = PL_FCI_IMPOSSIBLE; 00786 00787 if ( fci != PL_FCI_IMPOSSIBLE ) 00788 { 00789 i += 2; 00790 unicode_buffer[j] = fci; 00791 skip = 1; 00792 } 00793 break; 00794 00795 case 'g': /* Greek font */ 00796 case 'G': /* Greek font */ 00797 /* Get the index in the lookup table 00798 * 527 = upper case alpha displacement in Hershey Table 00799 * 627 = lower case alpha displacement in Hershey Table 00800 */ 00801 00802 ig = plP_strpos( plP_greek_mnemonic, string[i + 2] ); 00803 if ( ig >= 0 ) 00804 { 00805 if ( ig >= 24 ) 00806 ig = ig + 100 - 24; 00807 idx = plhershey2unicode( ig + 527 ); 00808 unicode_buffer[j++] = \ 00809 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode; 00810 i += 2; 00811 skip = 1; /* skip is set if we have copied something 00812 * into the unicode table */ 00813 } 00814 else 00815 { 00816 /* Use "unknown" unicode character if string[i+2] 00817 * is not in the Greek array.*/ 00818 unicode_buffer[j++] = (PLUNICODE) 0x00; 00819 i += 2; 00820 skip = 1; /* skip is set if we have copied something 00821 * into the unicode table */ 00822 } 00823 j--; 00824 break; 00825 } 00826 } 00827 00828 if ( skip == 0 ) 00829 { 00830 PLUNICODE unichar = 0; 00831 #ifdef HAVE_LIBUNICODE 00832 char * ptr = unicode_get_utf8( string + i, &unichar ); 00833 #else 00834 char * ptr = utf8_to_ucs4( string + i, &unichar ); 00835 #endif 00836 if ( ptr == NULL ) 00837 { 00838 char buf[BUFFER_SIZE]; 00839 char tmpstring[31]; 00840 strncpy( tmpstring, string, 30 ); 00841 tmpstring[30] = '\0'; 00842 snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s", 00843 tmpstring, strlen( string ) > 30 ? "[...]" : "" ); 00844 plabort( buf ); 00845 return; 00846 } 00847 unicode_buffer [j] = unichar; 00848 i += ptr - ( string + i ) - 1; 00849 00850 /* Search for escesc (an unescaped escape) in the input 00851 * string and adjust unicode_buffer accordingly). 00852 */ 00853 if ( unicode_buffer[j] == esc && string[i + 1] == esc ) 00854 { 00855 i++; 00856 unicode_buffer[++j] = esc; 00857 } 00858 } 00859 j++; 00860 } 00861 if ( j > 0 ) 00862 { 00863 args.unicode_array_len = j; /* Much easier to set the length than 00864 * work it out later :-) */ 00865 args.unicode_array = &unicode_buffer[0]; /* Get address of the 00866 * unicode buffer (even 00867 * though it is 00868 * currently static) */ 00869 } 00870 00871 00872 /* The alternate unicode text handling loop. */ 00873 00874 if ( plsc->alt_unicode ) 00875 { 00876 args.n_fci = fci; 00877 plP_esc( PLESC_BEGIN_TEXT, &args ); 00878 00879 for ( i = 0; i < len; i++ ) 00880 { 00881 skip = 0; 00882 00883 if ( string[i] == esc ) 00884 { 00885 switch ( string[i + 1] ) 00886 { 00887 case '(': /* hershey code */ 00888 i += 2 + text2num( &string[i + 2], ')', &code ); 00889 idx = plhershey2unicode( code ); 00890 args.n_char = \ 00891 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode; 00892 plP_esc( PLESC_TEXT_CHAR, &args ); 00893 00894 skip = 1; 00895 break; 00896 00897 case '[': /* unicode */ 00898 i += 2 + text2num( &string[i + 2], ']', &code ); 00899 args.n_char = code; 00900 plP_esc( PLESC_TEXT_CHAR, &args ); 00901 skip = 1; 00902 break; 00903 00904 case '<': /* change font*/ 00905 if ( '0' <= string[i + 2] && string[i + 2] <= '9' ) 00906 { 00907 i += 2 + text2num( &string[i + 2], '>', &code ); 00908 if ( code & PL_FCI_MARK ) 00909 { 00910 /* code is a complete FCI (font characterization 00911 * integer): change FCI to this value. 00912 */ 00913 fci = code; 00914 skip = 1; 00915 00916 args.n_fci = fci; 00917 args.n_ctrl_char = PLTEXT_FONTCHANGE; 00918 plP_esc( PLESC_CONTROL_CHAR, &args ); 00919 } 00920 else 00921 { 00922 /* code is not complete FCI. Change 00923 * FCI with hex power in rightmost hex 00924 * digit and hex digit value in second rightmost 00925 * hex digit. 00926 */ 00927 hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK; 00928 hexpower = code & PL_FCI_HEXPOWER_MASK; 00929 plP_hex2fci( hexdigit, hexpower, &fci ); 00930 skip = 1; 00931 00932 args.n_fci = fci; 00933 args.n_ctrl_char = PLTEXT_FONTCHANGE; 00934 plP_esc( PLESC_CONTROL_CHAR, &args ); 00935 } 00936 } 00937 else 00938 { 00939 i += text2fci( &string[i + 1], &hexdigit, &hexpower ); 00940 if ( hexpower < 7 ) 00941 { 00942 plP_hex2fci( hexdigit, hexpower, &fci ); 00943 skip = 1; 00944 00945 args.n_fci = fci; 00946 args.n_ctrl_char = PLTEXT_FONTCHANGE; 00947 plP_esc( PLESC_CONTROL_CHAR, &args ); 00948 } 00949 } 00950 break; 00951 00952 case 'f': /* Deprecated Hershey-style font change*/ 00953 case 'F': /* Deprecated Hershey-style font change*/ 00954 /* We implement an approximate response here so that 00955 * reasonable results are obtained for unicode fonts, 00956 * but this method is deprecated and the #<nnn> or 00957 * #<command string> methods should be used instead 00958 * to change unicode fonts in mid-string. 00959 */ 00960 fci = PL_FCI_MARK; 00961 if ( string[i + 2] == 'n' ) 00962 { 00963 /* medium, upright, sans-serif */ 00964 plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci ); 00965 } 00966 else if ( string[i + 2] == 'r' ) 00967 { 00968 /* medium, upright, serif */ 00969 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci ); 00970 } 00971 else if ( string[i + 2] == 'i' ) 00972 { 00973 /* medium, italic, serif */ 00974 plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci ); 00975 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci ); 00976 } 00977 else if ( string[i + 2] == 's' ) 00978 { 00979 /* medium, upright, script */ 00980 plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci ); 00981 } 00982 else 00983 fci = PL_FCI_IMPOSSIBLE; 00984 00985 if ( fci != PL_FCI_IMPOSSIBLE ) 00986 { 00987 i += 2; 00988 skip = 1; 00989 00990 args.n_fci = fci; 00991 args.n_ctrl_char = PLTEXT_FONTCHANGE; 00992 plP_esc( PLESC_CONTROL_CHAR, &args ); 00993 } 00994 break; 00995 00996 case 'g': /* Greek font */ 00997 case 'G': /* Greek font */ 00998 /* Get the index in the lookup table 00999 * 527 = upper case alpha displacement in Hershey Table 01000 * 627 = lower case alpha displacement in Hershey Table 01001 */ 01002 ig = plP_strpos( plP_greek_mnemonic, string[i + 2] ); 01003 if ( ig >= 0 ) 01004 { 01005 if ( ig >= 24 ) 01006 ig = ig + 100 - 24; 01007 idx = plhershey2unicode( ig + 527 ); 01008 i += 2; 01009 skip = 1; /* skip is set if we have copied something 01010 * into the unicode table */ 01011 01012 args.n_char = \ 01013 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode; 01014 plP_esc( PLESC_TEXT_CHAR, &args ); 01015 } 01016 else 01017 { 01018 /* Use "unknown" unicode character if string[i+2] 01019 * is not in the Greek array.*/ 01020 i += 2; 01021 skip = 1; /* skip is set if we have copied something 01022 * into the unicode table */ 01023 01024 args.n_char = \ 01025 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode; 01026 plP_esc( PLESC_TEXT_CHAR, &args ); 01027 } 01028 break; 01029 01030 case 'u': 01031 args.n_ctrl_char = PLTEXT_SUPERSCRIPT; 01032 plP_esc( PLESC_CONTROL_CHAR, &args ); 01033 i += 1; 01034 skip = 1; 01035 break; 01036 01037 case 'd': 01038 args.n_ctrl_char = PLTEXT_SUBSCRIPT; 01039 plP_esc( PLESC_CONTROL_CHAR, &args ); 01040 i += 1; 01041 skip = 1; 01042 break; 01043 } 01044 } 01045 01046 if ( skip == 0 ) 01047 { 01048 PLUNICODE unichar = 0; 01049 #ifdef HAVE_LIBUNICODE 01050 char * ptr = unicode_get_utf8( string + i, &unichar ); 01051 #else 01052 char * ptr = utf8_to_ucs4( string + i, &unichar ); 01053 #endif 01054 if ( ptr == NULL ) 01055 { 01056 char buf[BUFFER_SIZE]; 01057 char tmpstring[31]; 01058 strncpy( tmpstring, string, 30 ); 01059 tmpstring[30] = '\0'; 01060 snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s", 01061 tmpstring, strlen( string ) > 30 ? "[...]" : "" ); 01062 plabort( buf ); 01063 return; 01064 } 01065 i += ptr - ( string + i ) - 1; 01066 01067 /* Search for escesc (an unescaped escape) in the input 01068 * string and adjust unicode_buffer accordingly). 01069 */ 01070 if ( string[i] == esc && string[i + 1] == esc ) 01071 { 01072 i++; 01073 args.n_char = esc; 01074 } 01075 else 01076 { 01077 args.n_char = unichar; 01078 } 01079 plP_esc( PLESC_TEXT_CHAR, &args ); 01080 } 01081 } 01082 plP_esc( PLESC_END_TEXT, &args ); 01083 } 01084 01085 /* No text to display */ 01086 01087 if ( j == 0 ) 01088 return; 01089 } 01090 } 01091 01092 if ( plsc->dev_unicode ) 01093 { 01094 args.string = NULL; /* We are using unicode */ 01095 } 01096 else 01097 { 01098 args.string = string; 01099 } 01100 01101 plP_esc( PLESC_HAS_TEXT, &args ); 01102 01103 #ifndef DEBUG_TEXT 01104 } 01105 else 01106 { 01107 #endif 01108 plstr( base, xform, refx, refy, string ); 01109 } 01110 } 01111 01112 /* convert utf8 string to ucs4 unichar */ 01113 static char * 01114 utf8_to_ucs4( const char *ptr, PLUNICODE *unichar ) 01115 { 01116 char tmp; 01117 int isFirst = 1; 01118 int cnt = 0; 01119 01120 do 01121 { 01122 /* Get next character in string */ 01123 tmp = *ptr++; 01124 if ( isFirst ) /* First char in UTF8 sequence */ 01125 { 01126 isFirst = 0; 01127 /* Determine length of sequence */ 01128 if ( (unsigned char) ( tmp & 0x80 ) == 0x00 ) /* single char */ 01129 { 01130 *unichar = (unsigned int) tmp & 0x7F; 01131 cnt = 0; 01132 } 01133 else if ( (unsigned char) ( tmp & 0xE0 ) == 0xC0 ) /* 2 chars */ 01134 { 01135 *unichar = (unsigned int) tmp & 0x1F; 01136 cnt = 1; 01137 } 01138 else if ( (unsigned char) ( tmp & 0xF0 ) == 0xE0 ) /* 3 chars */ 01139 { 01140 *unichar = (unsigned char) tmp & 0x0F; 01141 cnt = 2; 01142 } 01143 else if ( (unsigned char) ( tmp & 0xF8 ) == 0xF0 ) /* 4 chars */ 01144 { 01145 *unichar = (unsigned char) tmp & 0x07; 01146 cnt = 3; 01147 } 01148 else if ( (unsigned char) ( tmp & 0xFC ) == 0xF8 ) /* 5 chars */ 01149 { 01150 *unichar = (unsigned char) tmp & 0x03; 01151 cnt = 4; 01152 } 01153 else if ( (unsigned char) ( tmp & 0xFE ) == 0xFC ) /* 6 chars */ 01154 { 01155 *unichar = (unsigned char) tmp & 0x01; 01156 cnt = 5; 01157 } 01158 else /* Malformed */ 01159 { 01160 ptr = NULL; 01161 cnt = 0; 01162 } 01163 } 01164 else /* Subsequent char in UTF8 sequence */ 01165 { 01166 if ( (unsigned char) ( tmp & 0xC0 ) == 0x80 ) 01167 { 01168 *unichar = ( *unichar << 6 ) | ( (unsigned int) tmp & 0x3F ); 01169 cnt--; 01170 } 01171 else /* Malformed */ 01172 { 01173 ptr = NULL; 01174 cnt = 0; 01175 } 01176 } 01177 } while ( cnt > 0 ); 01178 return (char *) ptr; 01179 } 01180 01181 /* convert ucs4 unichar to utf8 string */ 01182 int 01183 ucs4_to_utf8( PLUNICODE unichar, char *ptr ) 01184 { 01185 unsigned char *tmp; 01186 int len; 01187 01188 tmp = (unsigned char *) ptr; 01189 01190 if ( ( unichar & 0xffff80 ) == 0 ) /* single byte */ 01191 { 01192 *tmp = (unsigned char) unichar; 01193 tmp++; 01194 len = 1; 01195 } 01196 else if ( ( unichar & 0xfff800 ) == 0 ) /* two bytes */ 01197 { 01198 *tmp = (unsigned char) 0xc0 | ( unichar >> 6 ); 01199 tmp++; 01200 *tmp = (unsigned char) 0x80 | ( unichar & 0x3f ); 01201 tmp++; 01202 len = 2; 01203 } 01204 else if ( ( unichar & 0xff0000 ) == 0 ) /* three bytes */ 01205 { 01206 *tmp = (unsigned char) 0xe0 | ( unichar >> 12 ); 01207 tmp++; 01208 *tmp = (unsigned char) 0x80 | ( ( unichar >> 6 ) & 0x3f ); 01209 tmp++; 01210 *tmp = (unsigned char) 0x80 | ( unichar & 0x3f ); 01211 tmp++; 01212 len = 3; 01213 } 01214 else if ( ( unichar & 0xe0000 ) == 0 ) /* four bytes */ 01215 { 01216 *tmp = (unsigned char) 0xf0 | ( unichar >> 18 ); 01217 tmp++; 01218 *tmp = (unsigned char) 0x80 | ( ( unichar >> 12 ) & 0x3f ); 01219 tmp++; 01220 *tmp = (unsigned char) 0x80 | ( ( unichar >> 6 ) & 0x3f ); 01221 tmp++; 01222 *tmp = (unsigned char) 0x80 | ( unichar & 0x3f ); 01223 tmp++; 01224 len = 4; 01225 } 01226 else /* Illegal coding */ 01227 { 01228 len = 0; 01229 } 01230 *tmp = '\0'; 01231 01232 return len; 01233 } 01234 01235 static void 01236 grline( short *x, short *y, PLINT npts ) 01237 { 01238 char *save_locale = plsave_set_locale(); 01239 if ( !plsc->stream_closed ) 01240 { 01241 ( *plsc->dispatch_table->pl_line )( (struct PLStream_struct *) plsc, 01242 x[0], y[0], x[1], y[1] ); 01243 } 01244 plrestore_locale( save_locale ); 01245 } 01246 01247 static void 01248 grpolyline( short *x, short *y, PLINT npts ) 01249 { 01250 char *save_locale = plsave_set_locale(); 01251 if ( !plsc->stream_closed ) 01252 { 01253 ( *plsc->dispatch_table->pl_polyline )( (struct PLStream_struct *) plsc, 01254 x, y, npts ); 01255 } 01256 plrestore_locale( save_locale ); 01257 } 01258 01259 static void 01260 grfill( short *x, short *y, PLINT npts ) 01261 { 01262 char * save_locale; 01263 plsc->dev_npts = npts; 01264 plsc->dev_x = x; 01265 plsc->dev_y = y; 01266 01267 save_locale = plsave_set_locale(); 01268 if ( !plsc->stream_closed ) 01269 { 01270 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 01271 PLESC_FILL, NULL ); 01272 } 01273 plrestore_locale( save_locale ); 01274 } 01275 01276 static void 01277 grgradient( short *x, short *y, PLINT npts ) 01278 { 01279 char * save_locale; 01280 plsc->dev_npts = npts; 01281 plsc->dev_x = x; 01282 plsc->dev_y = y; 01283 01284 save_locale = plsave_set_locale(); 01285 if ( !plsc->stream_closed ) 01286 { 01287 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 01288 PLESC_GRADIENT, NULL ); 01289 } 01290 plrestore_locale( save_locale ); 01291 } 01292 01293 /*--------------------------------------------------------------------------*\ 01294 * void difilt 01295 * 01296 * Driver interface filter -- passes all coordinates through a variety 01297 * of filters. These include filters to change : 01298 * 01299 * - mapping of meta to physical coordinates 01300 * - plot orientation 01301 * - window into plot (zooms) 01302 * - window into device (i.e set margins) 01303 * 01304 * The filters are applied in the order specified above. Because the 01305 * orientation change comes first, subsequent window specifications affect 01306 * the new coordinates (i.e. after a 90 degree flip, what was x is now y). 01307 * This is the only way that makes sense from a graphical interface 01308 * (e.g. TCL/TK driver). 01309 * 01310 * Where appropriate, the page clip limits are modified. 01311 \*--------------------------------------------------------------------------*/ 01312 01313 void 01314 difilt( PLINT *xscl, PLINT *yscl, PLINT npts, 01315 PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma ) 01316 { 01317 PLINT i, x, y; 01318 01319 /* Map meta coordinates to physical coordinates */ 01320 01321 if ( plsc->difilt & PLDI_MAP ) 01322 { 01323 for ( i = 0; i < npts; i++ ) 01324 { 01325 xscl[i] = (PLINT) ( plsc->dimxax * xscl[i] + plsc->dimxb ); 01326 yscl[i] = (PLINT) ( plsc->dimyay * yscl[i] + plsc->dimyb ); 01327 } 01328 } 01329 01330 /* Change orientation */ 01331 01332 if ( plsc->difilt & PLDI_ORI ) 01333 { 01334 for ( i = 0; i < npts; i++ ) 01335 { 01336 x = (PLINT) ( plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb ); 01337 y = (PLINT) ( plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb ); 01338 xscl[i] = x; 01339 yscl[i] = y; 01340 } 01341 } 01342 01343 /* Change window into plot space */ 01344 01345 if ( plsc->difilt & PLDI_PLT ) 01346 { 01347 for ( i = 0; i < npts; i++ ) 01348 { 01349 xscl[i] = (PLINT) ( plsc->dipxax * xscl[i] + plsc->dipxb ); 01350 yscl[i] = (PLINT) ( plsc->dipyay * yscl[i] + plsc->dipyb ); 01351 } 01352 } 01353 01354 /* Change window into device space and set clip limits */ 01355 /* (this is the only filter that modifies them) */ 01356 01357 if ( plsc->difilt & PLDI_DEV ) 01358 { 01359 for ( i = 0; i < npts; i++ ) 01360 { 01361 xscl[i] = (PLINT) ( plsc->didxax * xscl[i] + plsc->didxb ); 01362 yscl[i] = (PLINT) ( plsc->didyay * yscl[i] + plsc->didyb ); 01363 } 01364 *clpxmi = plsc->diclpxmi; 01365 *clpxma = plsc->diclpxma; 01366 *clpymi = plsc->diclpymi; 01367 *clpyma = plsc->diclpyma; 01368 } 01369 else 01370 { 01371 *clpxmi = plsc->phyxmi; 01372 *clpxma = plsc->phyxma; 01373 *clpymi = plsc->phyymi; 01374 *clpyma = plsc->phyyma; 01375 } 01376 } 01377 01378 void 01379 sdifilt( short *xscl, short *yscl, PLINT npts, 01380 PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma ) 01381 { 01382 int i; 01383 short x, y; 01384 01385 /* Map meta coordinates to physical coordinates */ 01386 01387 if ( plsc->difilt & PLDI_MAP ) 01388 { 01389 for ( i = 0; i < npts; i++ ) 01390 { 01391 xscl[i] = (PLINT) ( plsc->dimxax * xscl[i] + plsc->dimxb ); 01392 yscl[i] = (PLINT) ( plsc->dimyay * yscl[i] + plsc->dimyb ); 01393 } 01394 } 01395 01396 /* Change orientation */ 01397 01398 if ( plsc->difilt & PLDI_ORI ) 01399 { 01400 for ( i = 0; i < npts; i++ ) 01401 { 01402 x = (PLINT) ( plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb ); 01403 y = (PLINT) ( plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb ); 01404 xscl[i] = x; 01405 yscl[i] = y; 01406 } 01407 } 01408 01409 /* Change window into plot space */ 01410 01411 if ( plsc->difilt & PLDI_PLT ) 01412 { 01413 for ( i = 0; i < npts; i++ ) 01414 { 01415 xscl[i] = (PLINT) ( plsc->dipxax * xscl[i] + plsc->dipxb ); 01416 yscl[i] = (PLINT) ( plsc->dipyay * yscl[i] + plsc->dipyb ); 01417 } 01418 } 01419 01420 /* Change window into device space and set clip limits */ 01421 /* (this is the only filter that modifies them) */ 01422 01423 if ( plsc->difilt & PLDI_DEV ) 01424 { 01425 for ( i = 0; i < npts; i++ ) 01426 { 01427 xscl[i] = (PLINT) ( plsc->didxax * xscl[i] + plsc->didxb ); 01428 yscl[i] = (PLINT) ( plsc->didyay * yscl[i] + plsc->didyb ); 01429 } 01430 *clpxmi = (PLINT) ( plsc->diclpxmi ); 01431 *clpxma = (PLINT) ( plsc->diclpxma ); 01432 *clpymi = (PLINT) ( plsc->diclpymi ); 01433 *clpyma = (PLINT) ( plsc->diclpyma ); 01434 } 01435 else 01436 { 01437 *clpxmi = plsc->phyxmi; 01438 *clpxma = plsc->phyxma; 01439 *clpymi = plsc->phyymi; 01440 *clpyma = plsc->phyyma; 01441 } 01442 } 01443 01444 /*--------------------------------------------------------------------------*\ 01445 * void difilt_clip 01446 * 01447 * This provides the transformed text clipping region for the benefit of 01448 * those drivers that render their own text. 01449 \*--------------------------------------------------------------------------*/ 01450 01451 void 01452 difilt_clip( PLINT *x_coords, PLINT *y_coords ) 01453 { 01454 PLINT x1c, x2c, y1c, y2c; 01455 01456 x1c = plsc->clpxmi; 01457 y1c = plsc->clpymi; 01458 x2c = plsc->clpxma; 01459 y2c = plsc->clpyma; 01460 x_coords[0] = x1c; 01461 x_coords[1] = x1c; 01462 x_coords[2] = x2c; 01463 x_coords[3] = x2c; 01464 y_coords[0] = y1c; 01465 y_coords[1] = y2c; 01466 y_coords[2] = y2c; 01467 y_coords[3] = y1c; 01468 difilt( x_coords, y_coords, 4, &x1c, &x2c, &y1c, &y2c ); 01469 } 01470 01471 01472 /*--------------------------------------------------------------------------*\ 01473 * void pldi_ini 01474 * 01475 * Updates driver interface, making sure everything is in order. 01476 * Even if filter is not being used, the defaults need to be set up. 01477 \*--------------------------------------------------------------------------*/ 01478 01479 static void 01480 setdef_diplt() 01481 { 01482 plsc->dipxmin = 0.0; 01483 plsc->dipxmax = 1.0; 01484 plsc->dipymin = 0.0; 01485 plsc->dipymax = 1.0; 01486 } 01487 01488 static void 01489 setdef_didev() 01490 { 01491 plsc->mar = 0.0; 01492 plsc->aspect = 0.0; 01493 plsc->jx = 0.0; 01494 plsc->jy = 0.0; 01495 } 01496 01497 static void 01498 setdef_diori() 01499 { 01500 plsc->diorot = 0.; 01501 } 01502 01503 static void 01504 pldi_ini( void ) 01505 { 01506 if ( plsc->level >= 1 ) 01507 { 01508 if ( plsc->difilt & PLDI_MAP ) /* Coordinate mapping */ 01509 calc_dimap(); 01510 01511 if ( plsc->difilt & PLDI_ORI ) /* Orientation */ 01512 calc_diori(); 01513 else 01514 setdef_diori(); 01515 01516 if ( plsc->difilt & PLDI_PLT ) /* Plot window */ 01517 calc_diplt(); 01518 else 01519 setdef_diplt(); 01520 01521 if ( plsc->difilt & PLDI_DEV ) /* Device window */ 01522 calc_didev(); 01523 else 01524 setdef_didev(); 01525 } 01526 } 01527 01528 /*--------------------------------------------------------------------------*\ 01529 * void pldid2pc 01530 * 01531 * Converts input values from relative device coordinates to relative plot 01532 * coordinates. This function must be called when selecting a plot window 01533 * from a display driver, since the coordinates chosen by the user are 01534 * necessarily device-specific. 01535 \*--------------------------------------------------------------------------*/ 01536 01537 void 01538 pldid2pc( PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax ) 01539 { 01540 PLFLT pxmin, pymin, pxmax, pymax; 01541 PLFLT sxmin, symin, sxmax, symax; 01542 PLFLT rxmin, rymin, rxmax, rymax; 01543 01544 if ( plsc->difilt & PLDI_DEV ) 01545 { 01546 pldebug( "pldid2pc", 01547 "Relative device coordinates (in): %f, %f, %f, %f\n", 01548 *xmin, *ymin, *xmax, *ymax ); 01549 01550 pxmin = plP_dcpcx( *xmin ); 01551 pymin = plP_dcpcy( *ymin ); 01552 pxmax = plP_dcpcx( *xmax ); 01553 pymax = plP_dcpcy( *ymax ); 01554 01555 sxmin = ( pxmin - plsc->didxb ) / plsc->didxax; 01556 symin = ( pymin - plsc->didyb ) / plsc->didyay; 01557 sxmax = ( pxmax - plsc->didxb ) / plsc->didxax; 01558 symax = ( pymax - plsc->didyb ) / plsc->didyay; 01559 01560 rxmin = plP_pcdcx( (PLINT) sxmin ); 01561 rymin = plP_pcdcy( (PLINT) symin ); 01562 rxmax = plP_pcdcx( (PLINT) sxmax ); 01563 rymax = plP_pcdcy( (PLINT) symax ); 01564 01565 *xmin = ( rxmin < 0 ) ? 0 : rxmin; 01566 *xmax = ( rxmax > 1 ) ? 1 : rxmax; 01567 *ymin = ( rymin < 0 ) ? 0 : rymin; 01568 *ymax = ( rymax > 1 ) ? 1 : rymax; 01569 01570 pldebug( "pldid2pc", 01571 "Relative plot coordinates (out): %f, %f, %f, %f\n", 01572 rxmin, rymin, rxmax, rymax ); 01573 } 01574 } 01575 01576 /*--------------------------------------------------------------------------*\ 01577 * void pldip2dc 01578 * 01579 * Converts input values from relative plot coordinates to relative 01580 * device coordinates. 01581 \*--------------------------------------------------------------------------*/ 01582 01583 void 01584 pldip2dc( PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax ) 01585 { 01586 PLFLT pxmin, pymin, pxmax, pymax; 01587 PLFLT sxmin, symin, sxmax, symax; 01588 PLFLT rxmin, rymin, rxmax, rymax; 01589 01590 if ( plsc->difilt & PLDI_DEV ) 01591 { 01592 pldebug( "pldip2pc", 01593 "Relative plot coordinates (in): %f, %f, %f, %f\n", 01594 *xmin, *ymin, *xmax, *ymax ); 01595 01596 pxmin = plP_dcpcx( *xmin ); 01597 pymin = plP_dcpcy( *ymin ); 01598 pxmax = plP_dcpcx( *xmax ); 01599 pymax = plP_dcpcy( *ymax ); 01600 01601 sxmin = pxmin * plsc->didxax + plsc->didxb; 01602 symin = pymin * plsc->didyay + plsc->didyb; 01603 sxmax = pxmax * plsc->didxax + plsc->didxb; 01604 symax = pymax * plsc->didyay + plsc->didyb; 01605 01606 rxmin = plP_pcdcx( (PLINT) sxmin ); 01607 rymin = plP_pcdcy( (PLINT) symin ); 01608 rxmax = plP_pcdcx( (PLINT) sxmax ); 01609 rymax = plP_pcdcy( (PLINT) symax ); 01610 01611 *xmin = ( rxmin < 0 ) ? 0 : rxmin; 01612 *xmax = ( rxmax > 1 ) ? 1 : rxmax; 01613 *ymin = ( rymin < 0 ) ? 0 : rymin; 01614 *ymax = ( rymax > 1 ) ? 1 : rymax; 01615 01616 pldebug( "pldip2pc", 01617 "Relative device coordinates (out): %f, %f, %f, %f\n", 01618 rxmin, rymin, rxmax, rymax ); 01619 } 01620 } 01621 01622 /*--------------------------------------------------------------------------*\ 01623 * void plsdiplt 01624 * 01625 * Set window into plot space 01626 \*--------------------------------------------------------------------------*/ 01627 01628 void 01629 c_plsdiplt( PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax ) 01630 { 01631 plsc->dipxmin = ( xmin < xmax ) ? xmin : xmax; 01632 plsc->dipxmax = ( xmin < xmax ) ? xmax : xmin; 01633 plsc->dipymin = ( ymin < ymax ) ? ymin : ymax; 01634 plsc->dipymax = ( ymin < ymax ) ? ymax : ymin; 01635 01636 if ( xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1. ) 01637 { 01638 plsc->difilt &= ~PLDI_PLT; 01639 return; 01640 } 01641 01642 plsc->difilt |= PLDI_PLT; 01643 pldi_ini(); 01644 } 01645 01646 /*--------------------------------------------------------------------------*\ 01647 * void plsdiplz 01648 * 01649 * Set window into plot space incrementally (zoom) 01650 \*--------------------------------------------------------------------------*/ 01651 01652 void 01653 c_plsdiplz( PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax ) 01654 { 01655 if ( plsc->difilt & PLDI_PLT ) 01656 { 01657 xmin = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmin; 01658 ymin = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymin; 01659 xmax = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmax; 01660 ymax = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymax; 01661 } 01662 01663 plsdiplt( xmin, ymin, xmax, ymax ); 01664 } 01665 01666 /*--------------------------------------------------------------------------*\ 01667 * void calc_diplt 01668 * 01669 * Calculate transformation coefficients to set window into plot space. 01670 * 01671 * Note: if driver has requested to handle these commands itself, we must 01672 * send the appropriate escape command. If the driver succeeds it will 01673 * cancel the filter operation. The command is deferred until this point 01674 * to ensure that the driver has been initialized. 01675 \*--------------------------------------------------------------------------*/ 01676 01677 static void 01678 calc_diplt( void ) 01679 { 01680 PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen; 01681 01682 if ( plsc->dev_di ) 01683 { 01684 char *save_locale = plsave_set_locale(); 01685 if ( !plsc->stream_closed ) 01686 { 01687 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 01688 PLESC_DI, NULL ); 01689 } 01690 plrestore_locale( save_locale ); 01691 } 01692 01693 if ( !( plsc->difilt & PLDI_PLT ) ) 01694 return; 01695 01696 pxmin = plP_dcpcx( plsc->dipxmin ); 01697 pxmax = plP_dcpcx( plsc->dipxmax ); 01698 pymin = plP_dcpcy( plsc->dipymin ); 01699 pymax = plP_dcpcy( plsc->dipymax ); 01700 01701 pxlen = pxmax - pxmin; 01702 pylen = pymax - pymin; 01703 pxlen = MAX( 1, pxlen ); 01704 pylen = MAX( 1, pylen ); 01705 01706 plsc->dipxax = plsc->phyxlen / (double) pxlen; 01707 plsc->dipyay = plsc->phyylen / (double) pylen; 01708 plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin; 01709 plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin; 01710 } 01711 01712 /*--------------------------------------------------------------------------*\ 01713 * void plgdiplt 01714 * 01715 * Retrieve current window into plot space 01716 \*--------------------------------------------------------------------------*/ 01717 01718 void 01719 c_plgdiplt( PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax ) 01720 { 01721 *p_xmin = plsc->dipxmin; 01722 *p_xmax = plsc->dipxmax; 01723 *p_ymin = plsc->dipymin; 01724 *p_ymax = plsc->dipymax; 01725 } 01726 01727 /*--------------------------------------------------------------------------*\ 01728 * void plsdidev 01729 * 01730 * Set window into device space using margin, aspect ratio, and 01731 * justification. If you want to just use the previous value for any of 01732 * these, just pass in the magic value PL_NOTSET. 01733 * 01734 * It is unlikely that one should ever need to change the aspect ratio 01735 * but it's in there for completeness. 01736 \*--------------------------------------------------------------------------*/ 01737 01738 void 01739 c_plsdidev( PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy ) 01740 { 01741 plsetvar( plsc->mar, mar ); 01742 plsetvar( plsc->aspect, aspect ); 01743 plsetvar( plsc->jx, jx ); 01744 plsetvar( plsc->jy, jy ); 01745 01746 if ( mar == 0. && aspect == 0. && jx == 0. && jy == 0. && 01747 !( plsc->difilt & PLDI_ORI ) ) 01748 { 01749 plsc->difilt &= ~PLDI_DEV; 01750 return; 01751 } 01752 01753 plsc->difilt |= PLDI_DEV; 01754 pldi_ini(); 01755 } 01756 01757 /*--------------------------------------------------------------------------*\ 01758 * void calc_didev 01759 * 01760 * Calculate transformation coefficients to set window into device space. 01761 * Calculates relative window bounds and calls plsdidxy to finish the job. 01762 \*--------------------------------------------------------------------------*/ 01763 01764 static void 01765 calc_didev( void ) 01766 { 01767 PLFLT lx, ly, aspect, aspdev; 01768 PLFLT xmin, xmax, xlen, ymin, ymax, ylen; 01769 PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen; 01770 01771 if ( plsc->dev_di ) 01772 { 01773 char *save_locale = plsave_set_locale(); 01774 if ( !plsc->stream_closed ) 01775 { 01776 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 01777 PLESC_DI, NULL ); 01778 } 01779 plrestore_locale( save_locale ); 01780 } 01781 01782 if ( !( plsc->difilt & PLDI_DEV ) ) 01783 return; 01784 01785 /* Calculate aspect ratio of physical device */ 01786 01787 lx = plsc->phyxlen / plsc->xpmm; 01788 ly = plsc->phyylen / plsc->ypmm; 01789 aspdev = lx / ly; 01790 01791 if ( plsc->difilt & PLDI_ORI ) 01792 aspect = plsc->aspori; 01793 else 01794 aspect = plsc->aspect; 01795 01796 if ( aspect <= 0. ) 01797 aspect = plsc->aspdev; 01798 01799 /* Failsafe */ 01800 01801 plsc->mar = ( plsc->mar > 0.5 ) ? 0.5 : plsc->mar; 01802 plsc->mar = ( plsc->mar < 0.0 ) ? 0.0 : plsc->mar; 01803 plsc->jx = ( plsc->jx > 0.5 ) ? 0.5 : plsc->jx; 01804 plsc->jx = ( plsc->jx < -0.5 ) ? -0.5 : plsc->jx; 01805 plsc->jy = ( plsc->jy > 0.5 ) ? 0.5 : plsc->jy; 01806 plsc->jy = ( plsc->jy < -0.5 ) ? -0.5 : plsc->jy; 01807 01808 /* Relative device coordinates that neutralize aspect ratio difference */ 01809 01810 xlen = ( aspect < aspdev ) ? ( aspect / aspdev ) : 1.0; 01811 ylen = ( aspect < aspdev ) ? 1.0 : ( aspdev / aspect ); 01812 01813 xlen *= ( 1.0 - 2. * plsc->mar ); 01814 ylen *= ( 1.0 - 2. * plsc->mar ); 01815 01816 xmin = ( 1. - xlen ) * ( 0.5 + plsc->jx ); 01817 xmax = xmin + xlen; 01818 01819 ymin = ( 1. - ylen ) * ( 0.5 + plsc->jy ); 01820 ymax = ymin + ylen; 01821 01822 /* Calculate transformation coefficients */ 01823 01824 pxmin = plP_dcpcx( xmin ); 01825 pxmax = plP_dcpcx( xmax ); 01826 pymin = plP_dcpcy( ymin ); 01827 pymax = plP_dcpcy( ymax ); 01828 01829 pxlen = pxmax - pxmin; 01830 pylen = pymax - pymin; 01831 pxlen = MAX( 1, pxlen ); 01832 pylen = MAX( 1, pylen ); 01833 01834 plsc->didxax = pxlen / (double) plsc->phyxlen; 01835 plsc->didyay = pylen / (double) plsc->phyylen; 01836 plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi; 01837 plsc->didyb = pymin - plsc->didyay * plsc->phyymi; 01838 01839 /* Set clip limits to conform to new page size */ 01840 01841 plsc->diclpxmi = (PLINT) ( plsc->didxax * plsc->phyxmi + plsc->didxb ); 01842 plsc->diclpxma = (PLINT) ( plsc->didxax * plsc->phyxma + plsc->didxb ); 01843 plsc->diclpymi = (PLINT) ( plsc->didyay * plsc->phyymi + plsc->didyb ); 01844 plsc->diclpyma = (PLINT) ( plsc->didyay * plsc->phyyma + plsc->didyb ); 01845 } 01846 01847 /*--------------------------------------------------------------------------*\ 01848 * void plgdidev 01849 * 01850 * Retrieve current window into device space 01851 \*--------------------------------------------------------------------------*/ 01852 01853 void 01854 c_plgdidev( PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy ) 01855 { 01856 *p_mar = plsc->mar; 01857 *p_aspect = plsc->aspect; 01858 *p_jx = plsc->jx; 01859 *p_jy = plsc->jy; 01860 } 01861 01862 /*--------------------------------------------------------------------------*\ 01863 * void plsdiori 01864 * 01865 * Set plot orientation, specifying rotation in units of pi/2. 01866 \*--------------------------------------------------------------------------*/ 01867 01868 void 01869 c_plsdiori( PLFLT rot ) 01870 { 01871 plsc->diorot = rot; 01872 if ( rot == 0. ) 01873 { 01874 plsc->difilt &= ~PLDI_ORI; 01875 pldi_ini(); 01876 return; 01877 } 01878 01879 plsc->difilt |= PLDI_ORI; 01880 pldi_ini(); 01881 } 01882 01883 /*--------------------------------------------------------------------------*\ 01884 * void calc_diori 01885 * 01886 * Calculate transformation coefficients to arbitrarily orient plot. 01887 * Preserve aspect ratios so the output doesn't suck. 01888 \*--------------------------------------------------------------------------*/ 01889 01890 static void 01891 calc_diori( void ) 01892 { 01893 PLFLT r11, r21, r12, r22, cost, sint; 01894 PLFLT x0, y0, lx, ly, aspect; 01895 PLFLT affine_result[NAFFINE], affine_left[NAFFINE]; 01896 01897 if ( plsc->dev_di ) 01898 { 01899 char *save_locale = plsave_set_locale(); 01900 if ( !plsc->stream_closed ) 01901 { 01902 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 01903 PLESC_DI, NULL ); 01904 } 01905 plrestore_locale( save_locale ); 01906 } 01907 01908 if ( !( plsc->difilt & PLDI_ORI ) ) 01909 return; 01910 01911 /* Center point of rotation */ 01912 01913 x0 = ( plsc->phyxma + plsc->phyxmi ) / 2.; 01914 y0 = ( plsc->phyyma + plsc->phyymi ) / 2.; 01915 01916 /* Rotation matrix */ 01917 01918 r11 = cos( plsc->diorot * PI / 2. ); 01919 r21 = sin( plsc->diorot * PI / 2. ); 01920 r12 = -r21; 01921 r22 = r11; 01922 01923 cost = ABS( r11 ); 01924 sint = ABS( r21 ); 01925 01926 /* Flip aspect ratio as necessary. Grungy but I don't see a better way */ 01927 01928 aspect = plsc->aspect; 01929 if ( aspect == 0. ) 01930 aspect = plsc->aspdev; 01931 01932 if ( plsc->freeaspect ) 01933 plsc->aspori = aspect; 01934 else 01935 plsc->aspori = ( aspect * cost + sint ) / ( aspect * sint + cost ); 01936 01937 if ( !( plsc->difilt & PLDI_DEV ) ) 01938 { 01939 plsc->difilt |= PLDI_DEV; 01940 setdef_didev(); 01941 } 01942 calc_didev(); 01943 01944 // Compute scale factors for relative device coordinates. Only 01945 // the aspect ratio of lx to ly matters. Note, plsc->phyxlen and 01946 // plsc->phyylen are in PLplot core library coordinates and don't 01947 // know anything about device coordinates which are likely to have 01948 // a quite different aspect ratio. So to correct between the two 01949 // coordinate systems must divide plsc->phyxlen/plsc->phyylen by 01950 // plsc->aspori. 01951 01952 // N.B. comment out this correction because causes other issues. 01953 01954 //lx = plsc->phyxlen/plsc->aspori; 01955 lx = plsc->phyxlen; 01956 ly = plsc->phyylen; 01957 01958 /* Transformation coefficients */ 01959 01960 /* 01961 * plsc->dioxax = r11; 01962 * plsc->dioxay = r21 * ( lx / ly ); 01963 * plsc->dioxb = ( 1. - r11 ) * x0 - r21 * y0 * ( lx / ly ); 01964 * 01965 * plsc->dioyax = r12 * ( ly / lx ); 01966 * plsc->dioyay = r22; 01967 * plsc->dioyb = ( 1. - r22 ) * y0 - r12 * x0 * ( ly / lx ); 01968 */ 01969 01970 /* Calculate affine transformation as product of translate to middle 01971 * of device, scale to relative device coordinates, rotate, unscale 01972 * to physical coordinates, untranslate to original zero point. */ 01973 plP_affine_translate( affine_result, x0, y0 ); 01974 plP_affine_scale( affine_left, lx, ly ); 01975 plP_affine_multiply( affine_result, affine_left, affine_result ); 01976 plP_affine_rotate( affine_left, plsc->diorot * 90. ); 01977 plP_affine_multiply( affine_result, affine_left, affine_result ); 01978 plP_affine_scale( affine_left, 1. / lx, 1. / ly ); 01979 plP_affine_multiply( affine_result, affine_left, affine_result ); 01980 plP_affine_translate( affine_left, -x0, -y0 ); 01981 plP_affine_multiply( affine_result, affine_left, affine_result ); 01982 plsc->dioxax = affine_result[0]; 01983 plsc->dioxay = affine_result[2]; 01984 plsc->dioxb = affine_result[4]; 01985 plsc->dioyax = affine_result[1]; 01986 plsc->dioyay = affine_result[3]; 01987 plsc->dioyb = affine_result[5]; 01988 } 01989 01990 /*--------------------------------------------------------------------------*\ 01991 * void plgdiori 01992 * 01993 * Get plot orientation 01994 \*--------------------------------------------------------------------------*/ 01995 01996 void 01997 c_plgdiori( PLFLT *p_rot ) 01998 { 01999 *p_rot = plsc->diorot; 02000 } 02001 02002 /*--------------------------------------------------------------------------*\ 02003 * void plsdimap 02004 * 02005 * Set up transformation from metafile coordinates. The size of the plot is 02006 * scaled so as to preserve aspect ratio. This isn't intended to be a 02007 * general-purpose facility just yet (not sure why the user would need it, 02008 * for one). 02009 \*--------------------------------------------------------------------------*/ 02010 02011 void 02012 c_plsdimap( PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax, 02013 PLFLT dimxpmm, PLFLT dimypmm ) 02014 { 02015 plsetvar( plsc->dimxmin, dimxmin ); 02016 plsetvar( plsc->dimxmax, dimxmax ); 02017 plsetvar( plsc->dimymin, dimymin ); 02018 plsetvar( plsc->dimymax, dimymax ); 02019 plsetvar( plsc->dimxpmm, dimxpmm ); 02020 plsetvar( plsc->dimypmm, dimypmm ); 02021 02022 plsc->difilt |= PLDI_MAP; 02023 pldi_ini(); 02024 } 02025 02026 /*--------------------------------------------------------------------------*\ 02027 * void calc_dimap 02028 * 02029 * Set up transformation from metafile coordinates. The size of the plot is 02030 * scaled so as to preserve aspect ratio. This isn't intended to be a 02031 * general-purpose facility just yet (not sure why the user would need it, 02032 * for one). 02033 \*--------------------------------------------------------------------------*/ 02034 02035 static void 02036 calc_dimap() 02037 { 02038 PLFLT lx, ly; 02039 PLINT pxmin, pxmax, pymin, pymax; 02040 PLFLT dimxlen, dimylen, pxlen, pylen; 02041 02042 if ( ( plsc->dimxmin == plsc->phyxmi ) && ( plsc->dimxmax == plsc->phyxma ) && 02043 ( plsc->dimymin == plsc->phyymi ) && ( plsc->dimymax == plsc->phyyma ) && 02044 ( plsc->dimxpmm == plsc->xpmm ) && ( plsc->dimypmm == plsc->ypmm ) ) 02045 { 02046 plsc->difilt &= ~PLDI_MAP; 02047 return; 02048 } 02049 02050 /* Set default aspect ratio */ 02051 02052 lx = ( plsc->dimxmax - plsc->dimxmin + 1 ) / plsc->dimxpmm; 02053 ly = ( plsc->dimymax - plsc->dimymin + 1 ) / plsc->dimypmm; 02054 02055 plsc->aspdev = lx / ly; 02056 02057 /* Build transformation to correct physical coordinates */ 02058 02059 dimxlen = plsc->dimxmax - plsc->dimxmin; 02060 dimylen = plsc->dimymax - plsc->dimymin; 02061 02062 pxmin = plsc->phyxmi; 02063 pxmax = plsc->phyxma; 02064 pymin = plsc->phyymi; 02065 pymax = plsc->phyyma; 02066 pxlen = pxmax - pxmin; 02067 pylen = pymax - pymin; 02068 02069 plsc->dimxax = pxlen / dimxlen; 02070 plsc->dimyay = pylen / dimylen; 02071 plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen; 02072 plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen; 02073 } 02074 02075 /*--------------------------------------------------------------------------*\ 02076 * void plflush() 02077 * 02078 * Flushes the output stream. Use sparingly, if at all. 02079 \*--------------------------------------------------------------------------*/ 02080 02081 void 02082 c_plflush( void ) 02083 { 02084 if ( plsc->dev_flush ) 02085 { 02086 char *save_locale = plsave_set_locale(); 02087 if ( !plsc->stream_closed ) 02088 { 02089 ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, 02090 PLESC_FLUSH, NULL ); 02091 } 02092 plrestore_locale( save_locale ); 02093 } 02094 else 02095 { 02096 if ( plsc->OutFile != NULL ) 02097 fflush( plsc->OutFile ); 02098 } 02099 } 02100 02101 /*--------------------------------------------------------------------------*\ 02102 * Startup routines. 02103 \*--------------------------------------------------------------------------*/ 02104 02105 /*--------------------------------------------------------------------------*\ 02106 * void pllib_init() 02107 * 02108 * Initialize library. Called internally by every startup routine. 02109 * Everything you want to always be initialized before plinit() is called 02110 * you should put here. E.g. dispatch table setup, rcfile read, etc. 02111 \*--------------------------------------------------------------------------*/ 02112 02113 void 02114 pllib_init() 02115 { 02116 if ( lib_initialized ) 02117 return; 02118 lib_initialized = 1; 02119 02120 #ifdef ENABLE_DYNDRIVERS 02121 /* Create libltdl resources */ 02122 lt_dlinit(); 02123 #endif 02124 02125 /* Initialize the dispatch table with the info from the static drivers table 02126 * and the available dynamic drivers. */ 02127 02128 plInitDispatchTable(); 02129 } 02130 02131 /*--------------------------------------------------------------------------*\ 02132 * void plstar(nx, ny) 02133 * 02134 * Initialize PLplot, passing in the windows/page settings. 02135 \*--------------------------------------------------------------------------*/ 02136 02137 void 02138 c_plstar( PLINT nx, PLINT ny ) 02139 { 02140 pllib_init(); 02141 02142 if ( plsc->level != 0 ) 02143 plend1(); 02144 02145 plssub( nx, ny ); 02146 02147 c_plinit(); 02148 } 02149 02150 /*--------------------------------------------------------------------------*\ 02151 * void plstart(devname, nx, ny) 02152 * 02153 * Initialize PLplot, passing the device name and windows/page settings. 02154 \*--------------------------------------------------------------------------*/ 02155 02156 void 02157 c_plstart( const char *devname, PLINT nx, PLINT ny ) 02158 { 02159 pllib_init(); 02160 02161 if ( plsc->level != 0 ) 02162 plend1(); 02163 02164 plssub( nx, ny ); 02165 plsdev( devname ); 02166 02167 c_plinit(); 02168 } 02169 02170 /*--------------------------------------------------------------------------*\ 02171 * void plinit() 02172 * 02173 * Initializes PLplot, using preset or default options. 02174 \*--------------------------------------------------------------------------*/ 02175 02176 void 02177 c_plinit( void ) 02178 { 02179 PLFLT def_arrow_x[6] = { -0.5, 0.5, 0.3, 0.5, 0.3, 0.5 }; 02180 PLFLT def_arrow_y[6] = { 0.0, 0.0, 0.2, 0.0, -0.2, 0.0 }; 02181 PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new; 02182 PLINT inc = 0, del = 2000; 02183 02184 pllib_init(); 02185 02186 if ( plsc->level != 0 ) 02187 plend1(); 02188 02189 /* Set stream number */ 02190 02191 plsc->ipls = ipls; 02192 02193 /* Set up devices */ 02194 02195 pllib_devinit(); 02196 02197 /* Auxiliary stream setup */ 02198 02199 plstrm_init(); 02200 02201 /* Set title for window to a sensible default if not defined */ 02202 if ( plsc->plwindow == NULL ) 02203 { 02204 if ( plsc->program ) 02205 { 02206 if ( ( plsc->plwindow = (char *) malloc( (size_t) ( 1 + strlen( plsc->program ) ) * sizeof ( char ) ) ) == NULL ) 02207 { 02208 plexit( "plinit: Insufficient memory" ); 02209 } 02210 strcpy( plsc->plwindow, plsc->program ); 02211 } 02212 else 02213 { 02214 if ( ( plsc->plwindow = (char *) malloc( (size_t) 7 * sizeof ( char ) ) ) == NULL ) 02215 { 02216 plexit( "plinit: Insufficient memory" ); 02217 } 02218 strcpy( plsc->plwindow, "PLplot" ); 02219 } 02220 } 02221 02222 /* Initialize device & first page */ 02223 02224 plP_init(); 02225 plP_bop(); 02226 plsc->level = 1; 02227 02228 02229 /* The driver options are freed after driver initialisation, 02230 * since it is assumed that in this function options are 02231 * processed and stored somewhere else. For further driver 02232 * initialisations (e.g. copy stream) there are no driver 02233 * options defined. */ 02234 02235 plP_FreeDrvOpts(); 02236 02237 /* Calculate factor such that the character aspect ratio is preserved 02238 * when the overall aspect ratio is changed, i.e., if portrait mode is 02239 * requested (only honored for subset of drivers) or if the aspect ratio 02240 * is specified in any way, or if a 90 deg rotation occurs with 02241 * -freeaspect. */ 02242 02243 /* Case where plsc->aspect has a value.... (e.g., -a aspect on the 02244 * command line or 2nd parameter of plsdidev specified) */ 02245 if ( plsc->aspect > 0. ) 02246 { 02247 lx = plsc->phyxlen / plsc->xpmm; 02248 ly = plsc->phyylen / plsc->ypmm; 02249 aspect_old = lx / ly; 02250 aspect_new = plsc->aspect; 02251 plsc->caspfactor = sqrt( aspect_old / aspect_new ); 02252 } 02253 /* Case of 90 deg rotations with -freeaspect (this is also how portrait 02254 * mode is implemented for the drivers that honor -portrait). */ 02255 else if ( plsc->freeaspect && ABS( cos( plsc->diorot * PI / 2. ) ) <= 1.e-5 ) 02256 { 02257 lx = plsc->phyxlen / plsc->xpmm; 02258 ly = plsc->phyylen / plsc->ypmm; 02259 aspect_old = lx / ly; 02260 aspect_new = ly / lx; 02261 plsc->caspfactor = sqrt( aspect_old / aspect_new ); 02262 } 02263 02264 else 02265 plsc->caspfactor = 1.; 02266 02267 /* Load fonts */ 02268 02269 plsc->cfont = 1; 02270 plfntld( initfont ); 02271 02272 /* Set up subpages */ 02273 02274 plP_subpInit(); 02275 02276 /* Set up number of allowed digits before switching to scientific notation */ 02277 /* The user can always change this */ 02278 02279 if ( plsc->xdigmax == 0 ) 02280 plsc->xdigmax = 4; 02281 02282 if ( plsc->ydigmax == 0 ) 02283 plsc->ydigmax = 4; 02284 02285 if ( plsc->zdigmax == 0 ) 02286 plsc->zdigmax = 3; 02287 02288 if ( plsc->timefmt == NULL ) 02289 c_pltimefmt( "%c" ); 02290 02291 /* Use default transformation between continuous and broken-down time 02292 * (and vice versa) if the transformation has not yet been defined 02293 * for this stream. */ 02294 if ( plsc->qsasconfig == NULL ) 02295 c_plconfigtime( 0., 0., 0., 0x0, 0, 0, 0, 0, 0, 0, 0. ); 02296 02297 /* Switch to graphics mode and set color and arrow style*/ 02298 02299 plgra(); 02300 plcol( 1 ); 02301 02302 pllsty( 1 ); 02303 plpat( 1, &inc, &del ); 02304 02305 plsvect( def_arrow_x, def_arrow_y, 6, 0 ); 02306 02307 /* Set clip limits. */ 02308 02309 plsc->clpxmi = plsc->phyxmi; 02310 plsc->clpxma = plsc->phyxma; 02311 plsc->clpymi = plsc->phyymi; 02312 plsc->clpyma = plsc->phyyma; 02313 02314 /* Page aspect ratio. */ 02315 02316 lx = plsc->phyxlen / plsc->xpmm; 02317 ly = plsc->phyylen / plsc->ypmm; 02318 plsc->aspdev = lx / ly; 02319 02320 /* Initialize driver interface */ 02321 02322 pldi_ini(); 02323 02324 /* Apply compensating factor to original xpmm and ypmm so that 02325 * character aspect ratio is preserved when overall aspect ratio 02326 * is changed. This must appear here in the code because previous 02327 * code in this routine and in routines that it calls must use the original 02328 * values of xpmm and ypmm before the compensating factor is applied. */ 02329 02330 plP_gpixmm( &xpmm_loc, &ypmm_loc ); 02331 plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor ); 02332 } 02333 02334 /*--------------------------------------------------------------------------*\ 02335 * void plend() 02336 * 02337 * End a plotting session for all open streams. 02338 \*--------------------------------------------------------------------------*/ 02339 02340 void 02341 c_plend( void ) 02342 { 02343 PLINT i; 02344 02345 if ( lib_initialized == 0 ) 02346 return; 02347 02348 for ( i = PL_NSTREAMS - 1; i >= 0; i-- ) 02349 { 02350 if ( pls[i] != NULL ) 02351 { 02352 plsstrm( i ); 02353 c_plend1(); 02354 } 02355 } 02356 plfontrel(); 02357 #ifdef ENABLE_DYNDRIVERS 02358 /* Release the libltdl resources */ 02359 lt_dlexit(); 02360 /* Free up memory allocated to the dispatch tables */ 02361 for ( i = 0; i < npldynamicdevices; i++ ) 02362 { 02363 free_mem( loadable_device_list[i].devnam ); 02364 free_mem( loadable_device_list[i].description ); 02365 free_mem( loadable_device_list[i].drvnam ); 02366 free_mem( loadable_device_list[i].tag ); 02367 } 02368 free_mem( loadable_device_list ); 02369 for ( i = 0; i < nloadabledrivers; i++ ) 02370 { 02371 free_mem( loadable_driver_list[i].drvnam ); 02372 } 02373 free_mem( loadable_driver_list ); 02374 for ( i = nplstaticdevices; i < npldrivers; i++ ) 02375 { 02376 free_mem( dispatch_table[i]->pl_MenuStr ); 02377 free_mem( dispatch_table[i]->pl_DevName ); 02378 free_mem( dispatch_table[i] ); 02379 } 02380 #endif 02381 for ( i = 0; i < nplstaticdevices; i++ ) 02382 { 02383 free_mem( dispatch_table[i] ); 02384 } 02385 free_mem( dispatch_table ); 02386 02387 lib_initialized = 0; 02388 } 02389 02390 /*--------------------------------------------------------------------------*\ 02391 * void plend1() 02392 * 02393 * End a plotting session for the current stream only. After the stream is 02394 * ended the memory associated with the stream's PLStream data structure is 02395 * freed (for stream > 0), and the stream counter is set to 0 (the default). 02396 \*--------------------------------------------------------------------------*/ 02397 02398 void 02399 c_plend1( void ) 02400 { 02401 if ( plsc->level > 0 ) 02402 { 02403 plP_eop(); 02404 plP_tidy(); 02405 plsc->level = 0; 02406 } 02407 /* Move from plP_tidy because FileName may be set even if level == 0 */ 02408 if ( plsc->FileName ) 02409 free_mem( plsc->FileName ); 02410 02411 /* Free all malloc'ed stream memory */ 02412 02413 free_mem( plsc->cmap0 ); 02414 free_mem( plsc->cmap1 ); 02415 free_mem( plsc->plwindow ); 02416 free_mem( plsc->geometry ); 02417 free_mem( plsc->dev ); 02418 free_mem( plsc->BaseName ); 02419 #ifndef BUFFERED_FILE 02420 free_mem( plsc->plbuf_buffer ); 02421 #endif 02422 if ( plsc->program ) 02423 free_mem( plsc->program ); 02424 if ( plsc->server_name ) 02425 free_mem( plsc->server_name ); 02426 if ( plsc->server_host ) 02427 free_mem( plsc->server_host ); 02428 if ( plsc->server_port ) 02429 free_mem( plsc->server_port ); 02430 if ( plsc->user ) 02431 free_mem( plsc->user ); 02432 if ( plsc->plserver ) 02433 free_mem( plsc->plserver ); 02434 if ( plsc->auto_path ) 02435 free_mem( plsc->auto_path ); 02436 02437 if ( plsc->arrow_x ) 02438 free_mem( plsc->arrow_x ); 02439 if ( plsc->arrow_y ) 02440 free_mem( plsc->arrow_y ); 02441 02442 if ( plsc->timefmt ) 02443 free_mem( plsc->timefmt ); 02444 02445 /* Close qsastime library for this stream that was opened by 02446 * plconfigtime call in plinit. */ 02447 02448 closeqsas( &( plsc->qsasconfig ) ); 02449 02450 /* Free malloc'ed stream if not in initial stream, else clear it out */ 02451 02452 if ( ipls > 0 ) 02453 { 02454 free_mem( plsc ); 02455 pls[ipls] = NULL; 02456 plsstrm( 0 ); 02457 } 02458 else 02459 { 02460 memset( (char *) pls[ipls], 0, sizeof ( PLStream ) ); 02461 } 02462 } 02463 02464 /*--------------------------------------------------------------------------*\ 02465 * void plsstrm 02466 * 02467 * Set stream number. If the data structure for a new stream is 02468 * unallocated, we allocate it here. 02469 \*--------------------------------------------------------------------------*/ 02470 02471 void 02472 c_plsstrm( PLINT strm ) 02473 { 02474 if ( strm < 0 || strm >= PL_NSTREAMS ) 02475 { 02476 fprintf( stderr, 02477 "plsstrm: Illegal stream number %d, must be in [0, %d]\n", 02478 (int) strm, PL_NSTREAMS ); 02479 } 02480 else 02481 { 02482 ipls = strm; 02483 if ( pls[ipls] == NULL ) 02484 { 02485 pls[ipls] = (PLStream *) malloc( (size_t) sizeof ( PLStream ) ); 02486 if ( pls[ipls] == NULL ) 02487 plexit( "plsstrm: Out of memory." ); 02488 02489 memset( (char *) pls[ipls], 0, sizeof ( PLStream ) ); 02490 } 02491 plsc = pls[ipls]; 02492 plsc->ipls = ipls; 02493 } 02494 } 02495 02496 /*--------------------------------------------------------------------------*\ 02497 * void plgstrm 02498 * 02499 * Get current stream number. 02500 \*--------------------------------------------------------------------------*/ 02501 02502 void 02503 c_plgstrm( PLINT *p_strm ) 02504 { 02505 *p_strm = ipls; 02506 } 02507 02508 /*--------------------------------------------------------------------------*\ 02509 * void plmkstrm 02510 * 02511 * Creates a new stream and makes it the default. Differs from using 02512 * plsstrm(), in that a free stream number is found, and returned. 02513 * 02514 * Unfortunately, I /have/ to start at stream 1 and work upward, since 02515 * stream 0 is preallocated. One of the BIG flaws in the PLplot API is 02516 * that no initial, library-opening call is required. So stream 0 must be 02517 * preallocated, and there is no simple way of determining whether it is 02518 * already in use or not. 02519 \*--------------------------------------------------------------------------*/ 02520 02521 void 02522 c_plmkstrm( PLINT *p_strm ) 02523 { 02524 int i; 02525 02526 for ( i = 1; i < PL_NSTREAMS; i++ ) 02527 { 02528 if ( pls[i] == NULL ) 02529 break; 02530 } 02531 02532 if ( i == PL_NSTREAMS ) 02533 { 02534 fprintf( stderr, "plmkstrm: Cannot create new stream\n" ); 02535 *p_strm = -1; 02536 } 02537 else 02538 { 02539 *p_strm = i; 02540 plsstrm( i ); 02541 } 02542 plstrm_init(); 02543 } 02544 02545 /*--------------------------------------------------------------------------*\ 02546 * void plstrm_init 02547 * 02548 * Does required startup initialization of a stream. Should be called right 02549 * after creating one (for allocating extra memory, etc). Users shouldn't 02550 * need to call this directly. 02551 * 02552 * This function can be called multiple times for a given stream, in which 02553 * case only the first call produces any effect. For streams >= 1, which 02554 * are created dynamically, this is called by the routine that allocates 02555 * the stream. Stream 0, which is preallocated, is much harder to deal with 02556 * because any of a number of different calls may be the first call to the 02557 * library. This is handled by just calling plstrm_init() from every 02558 * function that might be called first. Sucks, but it should work. 02559 \*--------------------------------------------------------------------------*/ 02560 02561 void 02562 plstrm_init( void ) 02563 { 02564 if ( !plsc->initialized ) 02565 { 02566 plsc->initialized = 1; 02567 02568 if ( plsc->cmap0 == NULL ) 02569 plspal0( "" ); 02570 02571 if ( plsc->cmap1 == NULL ) 02572 plspal1( "", TRUE ); 02573 } 02574 02575 plsc->psdoc = NULL; 02576 } 02577 02578 /*--------------------------------------------------------------------------*\ 02579 * pl_cpcolor 02580 * 02581 * Utility to copy one PLColor to another. 02582 \*--------------------------------------------------------------------------*/ 02583 02584 void 02585 pl_cpcolor( PLColor *to, PLColor *from ) 02586 { 02587 to->r = from->r; 02588 to->g = from->g; 02589 to->b = from->b; 02590 to->a = from->a; 02591 } 02592 02593 /*--------------------------------------------------------------------------*\ 02594 * void plcpstrm 02595 * 02596 * Copies state parameters from the reference stream to the current stream. 02597 * Tell driver interface to map device coordinates unless flags == 1. 02598 * 02599 * This function is used for making save files of selected plots (e.g. 02600 * from the TK driver). After initializing, you can get a copy of the 02601 * current plot to the specified device by switching to this stream and 02602 * issuing a plcpstrm() and a plreplot(), with calls to plbop() and 02603 * pleop() as appropriate. The plot buffer must have previously been 02604 * enabled (done automatically by some display drivers, such as X). 02605 \*--------------------------------------------------------------------------*/ 02606 02607 void 02608 c_plcpstrm( PLINT iplsr, PLINT flags ) 02609 { 02610 int i; 02611 PLStream *plsr; 02612 02613 plsr = pls[iplsr]; 02614 if ( plsr == NULL ) 02615 { 02616 fprintf( stderr, "plcpstrm: stream %d not in use\n", (int) iplsr ); 02617 return; 02618 } 02619 02620 /* May be debugging */ 02621 02622 plsc->debug = plsr->debug; 02623 02624 /* Plot buffer -- need to copy file pointer so that plreplot() works */ 02625 /* This also prevents inadvertent writes into the plot buffer */ 02626 02627 #ifdef BUFFERED_FILE 02628 plsc->plbufFile = plsr->plbufFile; 02629 #else 02630 plsc->plbuf_buffer_grow = plsr->plbuf_buffer_grow; 02631 plsc->plbuf_buffer_size = plsr->plbuf_buffer_size; 02632 plsc->plbuf_top = plsr->plbuf_top; 02633 plsc->plbuf_readpos = plsr->plbuf_readpos; 02634 if ( ( plsc->plbuf_buffer = malloc( plsc->plbuf_buffer_size ) ) == NULL ) 02635 plexit( "plcpstrm: Error allocating plot buffer." ); 02636 memcpy( plsc->plbuf_buffer, plsr->plbuf_buffer, plsr->plbuf_top ); 02637 #endif 02638 02639 /* Driver interface */ 02640 /* Transformation must be recalculated in current driver coordinates */ 02641 02642 if ( plsr->difilt & PLDI_PLT ) 02643 plsdiplt( plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax ); 02644 02645 if ( plsr->difilt & PLDI_DEV ) 02646 plsdidev( plsr->mar, plsr->aspect, plsr->jx, plsr->jy ); 02647 02648 if ( plsr->difilt & PLDI_ORI ) 02649 plsdiori( plsr->diorot ); 02650 02651 /* Map device coordinates */ 02652 02653 if ( !( flags & 0x01 ) ) 02654 { 02655 pldebug( "plcpstrm", "mapping parameters: %d %d %d %d %f %f\n", 02656 plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma, 02657 plsr->xpmm, plsr->ypmm ); 02658 plsdimap( plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma, 02659 plsr->xpmm, plsr->ypmm ); 02660 } 02661 02662 /* current color */ 02663 02664 pl_cpcolor( &plsc->curcolor, &plsr->curcolor ); 02665 02666 /* cmap 0 */ 02667 02668 plsc->icol0 = plsr->icol0; 02669 plsc->ncol0 = plsr->ncol0; 02670 if ( plsc->cmap0 != NULL ) 02671 free( (void *) plsc->cmap0 ); 02672 02673 if ( ( plsc->cmap0 = (PLColor *) calloc( 1, plsc->ncol0 * sizeof ( PLColor ) ) ) == NULL ) 02674 { 02675 plexit( "c_plcpstrm: Insufficient memory" ); 02676 } 02677 02678 for ( i = 0; i < plsc->ncol0; i++ ) 02679 pl_cpcolor( &plsc->cmap0[i], &plsr->cmap0[i] ); 02680 02681 /* cmap 1 */ 02682 02683 plsc->icol1 = plsr->icol1; 02684 plsc->ncol1 = plsr->ncol1; 02685 if ( plsc->cmap1 != NULL ) 02686 free( (void *) plsc->cmap1 ); 02687 02688 if ( ( plsc->cmap1 = (PLColor *) calloc( 1, plsc->ncol1 * sizeof ( PLColor ) ) ) == NULL ) 02689 { 02690 plexit( "c_plcpstrm: Insufficient memory" ); 02691 } 02692 02693 for ( i = 0; i < plsc->ncol1; i++ ) 02694 pl_cpcolor( &plsc->cmap1[i], &plsr->cmap1[i] ); 02695 02696 /* Initialize if it hasn't been done yet. */ 02697 02698 if ( plsc->level == 0 ) 02699 plinit(); 02700 } 02701 02702 /*--------------------------------------------------------------------------*\ 02703 * pllib_devinit() 02704 * 02705 * Does preliminary setup of device driver. 02706 * 02707 * This function (previously plGetDev) used to be what is now shown as 02708 * plSelectDev below. However, the situation is a bit more complicated now in 02709 * the dynloadable drivers era. We now have to: 02710 * 02711 * 1) Make sure the dispatch table is initialized to the union of static 02712 * drivers and available dynamic drivers (done from pllib_init now). 02713 * 2) Allow the user to select the desired device. 02714 * 3) Initialize the dispatch table entries for the selected device, in the 02715 * case that it is a dynloadable driver that has not yet been loaded. 02716 * 02717 * Also made non-static, in order to allow some device calls to be made prior 02718 * to calling plinit(). E.g. plframe needs to tell the X driver to create its 02719 * internal data structure during widget construction time (using the escape 02720 * function), but doesn't call plinit() until the plframe is actually mapped. 02721 \*--------------------------------------------------------------------------*/ 02722 02723 void 02724 pllib_devinit() 02725 { 02726 if ( plsc->dev_initialized ) 02727 return; 02728 plsc->dev_initialized = 1; 02729 02730 plSelectDev(); 02731 02732 plLoadDriver(); 02733 02734 /* offset by one since table is zero-based, but input list is not */ 02735 plsc->dispatch_table = dispatch_table[plsc->device - 1]; 02736 } 02737 02738 PLDLLIMPEXP int plInBuildTree() 02739 { 02740 static int inited = 0; 02741 static int inBuildTree = 0; 02742 02743 if ( inited == 0 ) 02744 { 02745 char currdir[PLPLOT_MAX_PATH]; 02746 char builddir[PLPLOT_MAX_PATH]; 02747 02748 if ( getcwd( currdir, PLPLOT_MAX_PATH ) == NULL ) 02749 { 02750 pldebug( "plInBuildTree():", "Not enough buffer space" ); 02751 } 02752 else 02753 { 02754 /* The chdir / getcwd call is to ensure we get the physical 02755 * path without any symlinks */ 02756 /* Ignore error in chdir - build tree may not exist */ 02757 if ( chdir( BUILD_DIR ) == 0 ) 02758 { 02759 if ( getcwd( builddir, PLPLOT_MAX_PATH ) == NULL ) 02760 { 02761 pldebug( "plInBuildTree():", "Not enough buffer space" ); 02762 } 02763 else 02764 { 02765 if ( strncmp( builddir, currdir, strlen( builddir ) ) == 0 ) 02766 { 02767 inBuildTree = 1; 02768 } 02769 } 02770 if ( chdir( currdir ) != 0 ) 02771 pldebug( "plInBuildTree():", "Unable to chdir to current directory" ); 02772 } 02773 } 02774 inited = 1; 02775 } 02776 return inBuildTree; 02777 } 02778 02779 #ifdef ENABLE_DYNDRIVERS 02780 02781 char* 02782 plGetDrvDir() 02783 { 02784 char* drvdir; 02785 02786 /* Get drivers directory in PLPLOT_DRV_DIR or DRV_DIR, 02787 * on this order 02788 */ 02789 02790 if ( plInBuildTree() == 1 ) 02791 { 02792 drvdir = BUILD_DIR "/drivers"; 02793 pldebug( "plGetDrvDir", "Using %s as the driver directory.\n", drvdir ); 02794 } 02795 else 02796 { 02797 pldebug( "plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n" ); 02798 drvdir = getenv( "PLPLOT_DRV_DIR" ); 02799 02800 if ( drvdir == NULL ) 02801 { 02802 pldebug( "plGetDrvDir", 02803 "Will use drivers dir: " DRV_DIR "\n" ); 02804 drvdir = DRV_DIR; 02805 } 02806 } 02807 02808 return drvdir; 02809 } 02810 02811 #endif 02812 02813 02814 /*--------------------------------------------------------------------------*\ 02815 * void plInitDispatchTable() 02816 * 02817 * ... 02818 \*--------------------------------------------------------------------------*/ 02819 02820 static int plDispatchSequencer( const void *p1, const void *p2 ) 02821 { 02822 const PLDispatchTable* t1 = *(PLDispatchTable **) p1; 02823 const PLDispatchTable* t2 = *(PLDispatchTable **) p2; 02824 02825 /* printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n", */ 02826 /* t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq ); */ 02827 02828 return t1->pl_seq - t2->pl_seq; 02829 } 02830 02831 static void 02832 plInitDispatchTable() 02833 { 02834 int n; 02835 02836 #ifdef ENABLE_DYNDRIVERS 02837 char buf[BUFFER2_SIZE]; 02838 char * drvdir; 02839 char *devnam, *devdesc, *devtype, *driver, *tag, *seqstr; 02840 int seq; 02841 int i, j, driver_found, done = 0; 02842 FILE *fp_drvdb = NULL; 02843 DIR * dp_drvdir = NULL; 02844 struct dirent* entry; 02845 /* lt_dlhandle dlhand; */ 02846 02847 /* Make sure driver counts are zeroed */ 02848 npldynamicdevices = 0; 02849 nloadabledrivers = 0; 02850 02851 /* Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings 02852 * will be stored */ 02853 fp_drvdb = pl_create_tempfile( NULL ); 02854 if ( fp_drvdb == NULL ) 02855 { 02856 plabort( "plInitDispatchTable: Could not open temporary file" ); 02857 return; 02858 } 02859 02860 /* Open the drivers directory */ 02861 drvdir = plGetDrvDir(); 02862 dp_drvdir = opendir( drvdir ); 02863 if ( dp_drvdir == NULL ) 02864 { 02865 fclose( fp_drvdb ); 02866 plabort( "plInitDispatchTable: Could not open drivers directory" ); 02867 return; 02868 } 02869 02870 /* Loop over each entry in the drivers directory */ 02871 02872 pldebug( "plInitDispatchTable", "Scanning dyndrivers dir\n" ); 02873 while ( ( entry = readdir( dp_drvdir ) ) != NULL ) 02874 { 02875 char* name = entry->d_name; 02876 int len = strlen( name ) - 3; 02877 02878 pldebug( "plInitDispatchTable", 02879 "Consider file %s\n", name ); 02880 02881 /* Only consider entries that have the ".rc" suffix */ 02882 if ( ( len > 0 ) && ( strcmp( name + len, ".rc" ) == 0 ) ) 02883 { 02884 char path[PLPLOT_MAX_PATH]; 02885 FILE * fd; 02886 02887 /* Open the driver's info file */ 02888 snprintf( path, PLPLOT_MAX_PATH, "%s/%s", drvdir, name ); 02889 fd = fopen( path, "r" ); 02890 if ( fd == NULL ) 02891 { 02892 closedir( dp_drvdir ); 02893 fclose( fp_drvdb ); 02894 snprintf( buf, BUFFER2_SIZE, 02895 "plInitDispatchTable: Could not open driver info file %s\n", 02896 name ); 02897 plabort( buf ); 02898 return; 02899 } 02900 02901 /* Each line in the <driver>.rc file corresponds to a specific device. 02902 * Write it to the drivers db file and take care of leading newline 02903 * character */ 02904 02905 pldebug( "plInitDispatchTable", 02906 "Opened driver info file %s\n", name ); 02907 while ( fgets( buf, BUFFER2_SIZE, fd ) != NULL ) 02908 { 02909 fprintf( fp_drvdb, "%s", buf ); 02910 if ( buf [strlen( buf ) - 1] != '\n' ) 02911 fprintf( fp_drvdb, "\n" ); 02912 npldynamicdevices++; 02913 } 02914 fclose( fd ); 02915 } 02916 } 02917 02918 /* Make sure that the temporary file containing the driversr database 02919 * is ready to read and close the directory handle */ 02920 fflush( fp_drvdb ); 02921 closedir( dp_drvdir ); 02922 02923 #endif 02924 02925 /* Allocate space for the dispatch table. */ 02926 if ( ( dispatch_table = (PLDispatchTable **) 02927 malloc( ( nplstaticdevices + npldynamicdevices ) * sizeof ( PLDispatchTable * ) ) ) == NULL ) 02928 { 02929 #ifdef ENABLE_DYNDRIVERS 02930 fclose( fp_drvdb ); 02931 #endif 02932 plexit( "plInitDispatchTable: Insufficient memory" ); 02933 } 02934 02935 /* Initialize the dispatch table entries for the static devices by calling 02936 * the dispatch table initialization function for each static device. This 02937 * is the same function that would be called at load time for dynamic 02938 * drivers. */ 02939 02940 for ( n = 0; n < nplstaticdevices; n++ ) 02941 { 02942 if ( ( dispatch_table[n] = (PLDispatchTable *) malloc( sizeof ( PLDispatchTable ) ) ) == NULL ) 02943 { 02944 #ifdef ENABLE_DYNDRIVERS 02945 fclose( fp_drvdb ); 02946 #endif 02947 plexit( "plInitDispatchTable: Insufficient memory" ); 02948 } 02949 02950 ( *static_device_initializers[n] )( dispatch_table[n] ); 02951 } 02952 npldrivers = nplstaticdevices; 02953 02954 #ifdef ENABLE_DYNDRIVERS 02955 02956 /* Allocate space for the device and driver specs. We may not use all of 02957 * these driver descriptors, but we obviously won't need more drivers than 02958 * devices... */ 02959 if ( ( ( loadable_device_list = malloc( npldynamicdevices * sizeof ( PLLoadableDevice ) ) ) == NULL ) || 02960 ( ( loadable_driver_list = malloc( npldynamicdevices * sizeof ( PLLoadableDriver ) ) ) == NULL ) ) 02961 { 02962 fclose( fp_drvdb ); 02963 plexit( "plInitDispatchTable: Insufficient memory" ); 02964 } 02965 02966 rewind( fp_drvdb ); 02967 02968 i = 0; 02969 done = !( i < npldynamicdevices ); 02970 while ( !done ) 02971 { 02972 char *p = fgets( buf, BUFFER2_SIZE, fp_drvdb ); 02973 02974 if ( p == 0 ) 02975 { 02976 done = 1; 02977 continue; 02978 } 02979 02980 devnam = strtok( buf, ":" ); 02981 devdesc = strtok( 0, ":" ); 02982 devtype = strtok( 0, ":" ); 02983 driver = strtok( 0, ":" ); 02984 seqstr = strtok( 0, ":" ); 02985 tag = strtok( 0, "\n" ); 02986 02987 seq = atoi( seqstr ); 02988 02989 n = npldrivers++; 02990 02991 if ( ( dispatch_table[n] = malloc( sizeof ( PLDispatchTable ) ) ) == NULL ) 02992 { 02993 fclose( fp_drvdb ); 02994 plexit( "plInitDispatchTable: Insufficient memory" ); 02995 } 02996 02997 /* Fill in the dispatch table entries. */ 02998 dispatch_table[n]->pl_MenuStr = plstrdup( devdesc ); 02999 dispatch_table[n]->pl_DevName = plstrdup( devnam ); 03000 dispatch_table[n]->pl_type = atoi( devtype ); 03001 dispatch_table[n]->pl_seq = seq; 03002 dispatch_table[n]->pl_init = 0; 03003 dispatch_table[n]->pl_line = 0; 03004 dispatch_table[n]->pl_polyline = 0; 03005 dispatch_table[n]->pl_eop = 0; 03006 dispatch_table[n]->pl_bop = 0; 03007 dispatch_table[n]->pl_tidy = 0; 03008 dispatch_table[n]->pl_state = 0; 03009 dispatch_table[n]->pl_esc = 0; 03010 03011 /* Add a record to the loadable device list */ 03012 loadable_device_list[i].devnam = plstrdup( devnam ); 03013 loadable_device_list[i].description = plstrdup( devdesc ); 03014 loadable_device_list[i].drvnam = plstrdup( driver ); 03015 loadable_device_list[i].tag = plstrdup( tag ); 03016 03017 /* Now see if this driver has been seen before. If not, add a driver 03018 * entry for it. */ 03019 driver_found = 0; 03020 for ( j = 0; j < nloadabledrivers; j++ ) 03021 if ( strcmp( driver, loadable_driver_list[j].drvnam ) == 0 ) 03022 { 03023 driver_found = 1; 03024 break; 03025 } 03026 03027 if ( !driver_found ) 03028 { 03029 loadable_driver_list[nloadabledrivers].drvnam = plstrdup( driver ); 03030 loadable_driver_list[nloadabledrivers].dlhand = 0; 03031 nloadabledrivers++; 03032 } 03033 03034 loadable_device_list[i].drvidx = j; 03035 03036 /* Get ready for next loadable device spec */ 03037 i++; 03038 } 03039 03040 /* RML: close fp_drvdb */ 03041 fclose( fp_drvdb ); 03042 03043 #endif 03044 03045 /* Finally, we need to sort the list into presentation order, based on the 03046 * sequence number in the dispatch ttable entries. */ 03047 03048 qsort( dispatch_table, npldrivers, sizeof ( PLDispatchTable* ), 03049 plDispatchSequencer ); 03050 } 03051 03052 /*--------------------------------------------------------------------------*\ 03053 * void plSelectDev() 03054 * 03055 * If the user has not already specified the output device, or the 03056 * one specified is either: (a) not available, (b) "?", or (c) NULL, the 03057 * user is prompted for it. 03058 * 03059 * Prompting quits after 10 unsuccessful tries in case the user has 03060 * run the program in the background with insufficient input. 03061 \*--------------------------------------------------------------------------*/ 03062 03063 static void 03064 plSelectDev() 03065 { 03066 int dev, i, count, length; 03067 char response[80]; 03068 char * devname_env; 03069 03070 /* If device name is not already specified, try to get it from environment */ 03071 03072 if ( plsc->DevName[0] == '\0' ) 03073 { 03074 devname_env = getenv( "PLPLOT_DEV" ); 03075 if ( devname_env ) 03076 { 03077 strncpy( plsc->DevName, devname_env, sizeof ( plsc->DevName ) - 1 ); 03078 plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0'; 03079 } 03080 } 03081 03082 /* Device name already specified. See if it is valid. */ 03083 03084 if ( *( plsc->DevName ) != '\0' && *( plsc->DevName ) != '?' ) 03085 { 03086 length = strlen( plsc->DevName ); 03087 for ( i = 0; i < npldrivers; i++ ) 03088 { 03089 if ( ( *plsc->DevName == *dispatch_table[i]->pl_DevName ) && 03090 ( strncmp( plsc->DevName, 03091 dispatch_table[i]->pl_DevName, length ) == 0 ) ) 03092 break; 03093 } 03094 if ( i < npldrivers ) 03095 { 03096 plsc->device = i + 1; 03097 return; 03098 } 03099 else 03100 { 03101 fprintf( stderr, "Requested device %s not available\n", 03102 plsc->DevName ); 03103 } 03104 } 03105 03106 dev = 0; 03107 count = 0; 03108 03109 if ( npldrivers == 1 ) 03110 dev = 1; 03111 03112 /* User hasn't specified it correctly yet, so we prompt */ 03113 03114 while ( dev < 1 || dev > npldrivers ) 03115 { 03116 fprintf( stdout, "\nPlotting Options:\n" ); 03117 for ( i = 0; i < npldrivers; i++ ) 03118 { 03119 fprintf( stdout, " <%2d> %-10s %s\n", i + 1, 03120 dispatch_table[i]->pl_DevName, 03121 dispatch_table[i]->pl_MenuStr ); 03122 } 03123 if ( ipls == 0 ) 03124 fprintf( stdout, "\nEnter device number or keyword: " ); 03125 else 03126 fprintf( stdout, "\nEnter device number or keyword (stream %d): ", 03127 (int) ipls ); 03128 03129 plio_fgets( response, sizeof ( response ), stdin ); 03130 03131 /* First check to see if device keyword was entered. */ 03132 /* Final "\n" in response messes things up, so ignore it. */ 03133 03134 length = strlen( response ); 03135 if ( *( response - 1 + length ) == '\n' ) 03136 length--; 03137 03138 for ( i = 0; i < npldrivers; i++ ) 03139 { 03140 if ( !strncmp( response, dispatch_table[i]->pl_DevName, 03141 (unsigned int) length ) ) 03142 break; 03143 } 03144 if ( i < npldrivers ) 03145 { 03146 dev = i + 1; 03147 } 03148 else 03149 { 03150 if ( ( dev = atoi( response ) ) < 1 ) 03151 { 03152 fprintf( stdout, "\nInvalid device: %s", response ); 03153 dev = 0; 03154 } 03155 } 03156 if ( count++ > 10 ) 03157 plexit( "plSelectDev: Too many tries." ); 03158 } 03159 plsc->device = dev; 03160 strcpy( plsc->DevName, dispatch_table[dev - 1]->pl_DevName ); 03161 } 03162 03163 /*--------------------------------------------------------------------------*\ 03164 * void plLoadDriver() 03165 * 03166 * Make sure the selected driver is loaded. Static drivers are already 03167 * loaded, but if the user selected a dynamically loadable driver, we may 03168 * have to take care of that now. 03169 \*--------------------------------------------------------------------------*/ 03170 03171 static void 03172 plLoadDriver( void ) 03173 { 03174 #ifdef ENABLE_DYNDRIVERS 03175 int i, drvidx; 03176 char sym[BUFFER_SIZE]; 03177 char *tag; 03178 03179 int n = plsc->device - 1; 03180 PLDispatchTable *dev = dispatch_table[n]; 03181 PLLoadableDriver *driver = 0; 03182 03183 /* If the dispatch table is already filled in, then either the device was 03184 * linked in statically, or else perhaps it was already loaded. In either 03185 * case, we have nothing left to do. */ 03186 if ( dev->pl_init ) 03187 return; 03188 03189 pldebug( "plLoadDriver", "Device not loaded!\n" ); 03190 03191 /* Now search through the list of loadable devices, looking for the record 03192 * that corresponds to the requested device. */ 03193 for ( i = 0; i < npldynamicdevices; i++ ) 03194 if ( strcmp( dev->pl_DevName, loadable_device_list[i].devnam ) == 0 ) 03195 break; 03196 03197 /* If we couldn't find such a record, then there is some sort of internal 03198 * logic flaw since plSelectDev is supposed to only select a valid device. 03199 */ 03200 if ( i == npldynamicdevices ) 03201 { 03202 fprintf( stderr, "No such device: %s.\n", dev->pl_DevName ); 03203 plexit( "plLoadDriver detected device logic screwup" ); 03204 } 03205 03206 /* Note the device tag, and the driver index. Note that a given driver could 03207 * supply multiple devices, each with a unique tag to distinguish the driver 03208 * entry points for the differnet supported devices. */ 03209 tag = loadable_device_list[i].tag; 03210 drvidx = loadable_device_list[i].drvidx; 03211 03212 pldebug( "plLoadDriver", "tag=%s, drvidx=%d\n", tag, drvidx ); 03213 03214 driver = &loadable_driver_list[drvidx]; 03215 03216 /* Load the driver if it hasn't been loaded yet. */ 03217 if ( !driver->dlhand ) 03218 { 03219 char drvspec[ DRVSPEC_SIZE ]; 03220 #if defined ( LTDL_WIN32 ) || defined ( __CYGWIN__ ) 03221 snprintf( drvspec, DRVSPEC_SIZE, "%s", driver->drvnam ); 03222 #else 03223 snprintf( drvspec, DRVSPEC_SIZE, "%s/%s", plGetDrvDir(), driver->drvnam ); 03224 #endif /* LTDL_WIN32 */ 03225 03226 pldebug( "plLoadDriver", "Trying to load %s on %s\n", 03227 driver->drvnam, drvspec ); 03228 03229 driver->dlhand = lt_dlopenext( drvspec ); 03230 } 03231 03232 /* If it still isn't loaded, then we're doomed. */ 03233 if ( !driver->dlhand ) 03234 { 03235 pldebug( "plLoadDriver", "lt_dlopenext failed because of " 03236 "the following reason:\n%s\n", lt_dlerror() ); 03237 fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam ); 03238 plexit( "Unable to load driver" ); 03239 } 03240 03241 /* Now we are ready to ask the driver's device dispatch init function to 03242 * initialize the entries in the dispatch table. */ 03243 03244 snprintf( sym, BUFFER_SIZE, "plD_dispatch_init_%s", tag ); 03245 { 03246 PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym ); 03247 if ( !dispatch_init ) 03248 { 03249 fprintf( stderr, 03250 "Unable to locate dispatch table initialization function for driver: %s.\n", 03251 driver->drvnam ); 03252 return; 03253 } 03254 03255 ( *dispatch_init )( dev ); 03256 } 03257 #endif 03258 } 03259 03260 /*--------------------------------------------------------------------------*\ 03261 * void plfontld() 03262 * 03263 * Load specified font set. 03264 \*--------------------------------------------------------------------------*/ 03265 03266 void 03267 c_plfontld( PLINT ifont ) 03268 { 03269 if ( ifont != 0 ) 03270 ifont = 1; 03271 03272 if ( plsc->level > 0 ) 03273 plfntld( ifont ); 03274 else 03275 initfont = ifont; 03276 } 03277 03278 /*--------------------------------------------------------------------------*\ 03279 * void plreplot() 03280 * 03281 * Replays contents of plot buffer to current device/file. 03282 \*--------------------------------------------------------------------------*/ 03283 03284 void 03285 c_plreplot( void ) 03286 { 03287 #ifdef BUFFERED_FILE 03288 if ( plsc->plbufFile != NULL ) 03289 { 03290 #else 03291 if ( plsc->plbuf_buffer != NULL ) 03292 { 03293 #endif 03294 plRemakePlot( plsc ); 03295 } 03296 else 03297 { 03298 plwarn( "plreplot: plot buffer not available" ); 03299 } 03300 } 03301 03302 /*--------------------------------------------------------------------------*\ 03303 * void plgFileDevs() 03304 * 03305 * Returns a list of file-oriented device names and their menu strings, 03306 * for use in a graphical interface. The caller must allocate enough 03307 * space for (*p_menustr) and (*p_devname) to hold a pointer for each 03308 * device -- 20 or so is plenty. E.g. char *menustr[20]. The size of 03309 * these arrays should be passed in *p_ndev, which, on exit, holds the 03310 * number of devices actually present. 03311 \*--------------------------------------------------------------------------*/ 03312 03313 void 03314 plgFileDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev ) 03315 { 03316 plgdevlst( *p_menustr, *p_devname, p_ndev, 0 ); 03317 } 03318 03319 /*--------------------------------------------------------------------------*\ 03320 * void plgDevs() 03321 * 03322 * Like plgFileDevs(), but returns names and menu strings for all devices. 03323 \*--------------------------------------------------------------------------*/ 03324 03325 void 03326 plgDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev ) 03327 { 03328 plgdevlst( *p_menustr, *p_devname, p_ndev, -1 ); 03329 } 03330 03331 static void 03332 plgdevlst( const char **p_menustr, const char **p_devname, int *p_ndev, int type ) 03333 { 03334 int i, j; 03335 03336 pllib_init(); 03337 03338 for ( i = j = 0; i < npldrivers; i++ ) 03339 { 03340 if ( type < 0 || dispatch_table[i]->pl_type == type ) 03341 { 03342 p_menustr[j] = dispatch_table[i]->pl_MenuStr; 03343 p_devname[j] = dispatch_table[i]->pl_DevName; 03344 if ( ++j + 1 >= *p_ndev ) 03345 { 03346 plwarn( "plgdevlst: too many devices" ); 03347 break; 03348 } 03349 } 03350 } 03351 p_menustr[j] = NULL; 03352 p_devname[j] = NULL; 03353 *p_ndev = j; 03354 } 03355 03356 /*--------------------------------------------------------------------------*\ 03357 * Various external access routines. 03358 \*--------------------------------------------------------------------------*/ 03359 03360 /* Get output device parameters. */ 03361 03362 void 03363 c_plgpage( PLFLT *p_xp, PLFLT *p_yp, 03364 PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff ) 03365 { 03366 *p_xp = plsc->xdpi; 03367 *p_yp = plsc->ydpi; 03368 *p_xleng = plsc->xlength; 03369 *p_yleng = plsc->ylength; 03370 *p_xoff = plsc->xoffset; 03371 *p_yoff = plsc->yoffset; 03372 } 03373 03374 /* Set output device parameters. Usually ignored by the driver. */ 03375 03376 void 03377 c_plspage( PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff ) 03378 { 03379 if ( plsc->level > 0 ) 03380 plwarn( "calling plspage() after plinit() may give unpredictable results" ); 03381 03382 if ( xp ) 03383 plsc->xdpi = xp; 03384 if ( yp ) 03385 plsc->ydpi = yp; 03386 03387 if ( xleng ) 03388 plsc->xlength = xleng; 03389 if ( yleng ) 03390 plsc->ylength = yleng; 03391 03392 if ( xoff ) 03393 plsc->xoffset = xoff; 03394 if ( yoff ) 03395 plsc->yoffset = yoff; 03396 03397 plsc->pageset = 1; 03398 } 03399 03400 /* Set the number of subwindows in x and y */ 03401 03402 void 03403 c_plssub( PLINT nx, PLINT ny ) 03404 { 03405 if ( nx > 0 ) 03406 plsc->nsubx = nx; 03407 if ( ny > 0 ) 03408 plsc->nsuby = ny; 03409 03410 /* Force a page advance */ 03411 03412 if ( plsc->level > 0 ) 03413 { 03414 plP_subpInit(); 03415 /*AWI plP_eop(); 03416 * plP_bop();*/ 03417 } 03418 } 03419 03420 /* Set the device (keyword) name */ 03421 03422 void 03423 c_plsdev( const char *devname ) 03424 { 03425 if ( plsc->level > 0 ) 03426 { 03427 plwarn( "plsdev: Must be called before plinit." ); 03428 return; 03429 } 03430 if ( devname != NULL ) 03431 { 03432 strncpy( plsc->DevName, devname, sizeof ( plsc->DevName ) - 1 ); 03433 plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0'; 03434 } 03435 } 03436 03437 /* Get the current device (keyword) name */ 03438 /* Note: you MUST have allocated space for this (80 characters is safe) */ 03439 03440 void 03441 c_plgdev( char *p_dev ) 03442 { 03443 strcpy( p_dev, plsc->DevName ); 03444 } 03445 03446 /* Set the memory area to be plotted (with the 'mem' driver) as the 'dev' 03447 * member of the stream structure. Also set the number 03448 * of pixels in the memory passed in in 'plotmem'. 03449 * Plotmem is a block of memory maxy by maxx by 3 bytes long, say: 03450 * 480 x 640 x 3 (Y, X, RGB) 03451 * 03452 * This memory will be freed by the user! 03453 */ 03454 03455 void 03456 c_plsmem( PLINT maxx, PLINT maxy, void *plotmem ) 03457 { 03458 plsc->dev = plotmem; 03459 plP_setphy( 0, maxx, 0, maxy ); 03460 } 03461 03462 /* Get the current stream pointer */ 03463 03464 void 03465 plgpls( PLStream **p_pls ) 03466 { 03467 *p_pls = plsc; 03468 } 03469 03470 /* Get the (current) run level. 03471 * Valid settings are: 03472 * 0 uninitialized 03473 * 1 initialized 03474 * 2 viewport defined 03475 * 3 world coords defined 03476 */ 03477 03478 void 03479 c_plglevel( PLINT *p_level ) 03480 { 03481 *p_level = plsc->level; 03482 } 03483 03484 /* Set the function pointer for the keyboard event handler */ 03485 03486 void 03487 plsKeyEH( void ( *KeyEH )( PLGraphicsIn *, void *, int * ), 03488 void *KeyEH_data ) 03489 { 03490 plsc->KeyEH = KeyEH; 03491 plsc->KeyEH_data = KeyEH_data; 03492 } 03493 03494 /* Set the function pointer for the (mouse) button event handler */ 03495 03496 void 03497 plsButtonEH( void ( *ButtonEH )( PLGraphicsIn *, void *, int * ), 03498 void *ButtonEH_data ) 03499 { 03500 plsc->ButtonEH = ButtonEH; 03501 plsc->ButtonEH_data = ButtonEH_data; 03502 } 03503 03504 /* Sets an optional user bop handler. */ 03505 03506 void 03507 plsbopH( void ( *handler )( void *, int * ), void *handler_data ) 03508 { 03509 plsc->bop_handler = handler; 03510 plsc->bop_data = handler_data; 03511 } 03512 03513 /* Sets an optional user eop handler. */ 03514 03515 void 03516 plseopH( void ( *handler )( void *, int * ), void *handler_data ) 03517 { 03518 plsc->eop_handler = handler; 03519 plsc->eop_data = handler_data; 03520 } 03521 03522 /* Set the variables to be used for storing error info */ 03523 03524 void 03525 plsError( PLINT *errcode, char *errmsg ) 03526 { 03527 if ( errcode != NULL ) 03528 plsc->errcode = errcode; 03529 03530 if ( errmsg != NULL ) 03531 plsc->errmsg = errmsg; 03532 } 03533 03534 /* Set orientation. Must be done before calling plinit. */ 03535 03536 void 03537 c_plsori( PLINT ori ) 03538 { 03539 plsdiori( (PLFLT) ori ); 03540 } 03541 03542 /* 03543 * Set pen width. Can be done any time, but before calling plinit is best 03544 * since otherwise it may be volatile (i.e. reset on next page advance). 03545 * If width < 0 or is unchanged by the call, nothing is done. 03546 */ 03547 03548 void 03549 c_plwid( PLINT width ) 03550 { 03551 if ( width != plsc->width && width >= 0 ) 03552 { 03553 plsc->width = width; 03554 03555 if ( plsc->level > 0 ) 03556 { 03557 if ( !plsc->widthlock ) 03558 plP_state( PLSTATE_WIDTH ); 03559 } 03560 } 03561 } 03562 03563 /* Set the output file pointer */ 03564 03565 void 03566 plgfile( FILE **p_file ) 03567 { 03568 *p_file = plsc->OutFile; 03569 } 03570 03571 /* Get the output file pointer */ 03572 03573 void 03574 plsfile( FILE *file ) 03575 { 03576 plsc->OutFile = file; 03577 } 03578 03579 /* Get the (current) output file name. Must be preallocated to >=80 bytes */ 03580 /* Beyond that, I truncate it. You have been warned. */ 03581 03582 void 03583 c_plgfnam( char *fnam ) 03584 { 03585 if ( fnam == NULL ) 03586 { 03587 plabort( "filename string must be preallocated to >=80 bytes" ); 03588 return; 03589 } 03590 03591 *fnam = '\0'; 03592 if ( plsc->FileName != NULL ) 03593 { 03594 strncpy( fnam, plsc->FileName, 79 ); 03595 fnam[79] = '\0'; 03596 } 03597 } 03598 03599 /* Set the output file name. */ 03600 03601 void 03602 c_plsfnam( const char *fnam ) 03603 { 03604 plP_sfnam( plsc, fnam ); 03605 } 03606 03607 /* Set the pause (on end-of-page) status */ 03608 03609 void 03610 c_plspause( PLINT pause ) 03611 { 03612 plsc->nopause = !pause; 03613 } 03614 03615 /* Set the floating point precision (in number of places) in numeric labels. */ 03616 03617 void 03618 c_plprec( PLINT setp, PLINT prec ) 03619 { 03620 plsc->setpre = setp; 03621 plsc->precis = prec; 03622 } 03623 03624 /* Get the floating point precision (in number of places) in numeric labels. */ 03625 03626 void 03627 plP_gprec( PLINT *p_setp, PLINT *p_prec ) 03628 { 03629 *p_setp = plsc->setpre; 03630 *p_prec = plsc->precis; 03631 } 03632 03633 const char * 03634 plP_gtimefmt() 03635 { 03636 return (const char *) plsc->timefmt; 03637 } 03638 03639 /* 03640 * Set the escape character for text strings. 03641 * From C you can pass as a character, from Fortran it needs to be the decimal 03642 * ASCII value. Only selected characters are allowed to prevent the user from 03643 * shooting himself in the foot (a '\' isn't allowed since it conflicts with 03644 * C's use of backslash as a character escape). 03645 */ 03646 03647 void 03648 c_plsesc( char esc ) 03649 { 03650 switch ( esc ) 03651 { 03652 case '!': /* ASCII 33 */ 03653 case '#': /* ASCII 35 */ 03654 case '$': /* ASCII 36 */ 03655 case '%': /* ASCII 37 */ 03656 case '&': /* ASCII 38 */ 03657 case '*': /* ASCII 42 */ 03658 case '@': /* ASCII 64 */ 03659 case '^': /* ASCII 94 */ 03660 case '~': /* ASCII 126 */ 03661 plsc->esc = esc; 03662 break; 03663 03664 default: 03665 plwarn( "plsesc: Invalid escape character, ignoring." ); 03666 } 03667 } 03668 03669 /* Get the escape character for text strings. */ 03670 03671 void 03672 plgesc( char *p_esc ) 03673 { 03674 if ( plsc->esc == '\0' ) 03675 plsc->esc = '#'; 03676 03677 *p_esc = plsc->esc; 03678 } 03679 03680 /* Set the FCI (font characterization integer) for unicode-enabled device 03681 * drivers. 03682 */ 03683 void 03684 c_plsfci( PLUNICODE fci ) 03685 { 03686 /* Always mark FCI as such. */ 03687 plsc->fci = fci | PL_FCI_MARK; 03688 } 03689 03690 /* Get the FCI (font characterization integer) for unicode-enabled device 03691 * drivers. 03692 */ 03693 void 03694 c_plgfci( PLUNICODE *pfci ) 03695 { 03696 /* Always mark FCI as such. */ 03697 *pfci = plsc->fci | PL_FCI_MARK; 03698 } 03699 /* Store hex digit value shifted to the left by hexdigit hexadecimal digits 03700 * into pre-existing FCI. 03701 */ 03702 void 03703 plP_hex2fci( unsigned char hexdigit, unsigned char hexpower, PLUNICODE *pfci ) 03704 { 03705 PLUNICODE mask; 03706 hexpower = hexpower & PL_FCI_HEXPOWER_MASK; 03707 mask = ~( ( (PLUNICODE) PL_FCI_HEXDIGIT_MASK ) << ( (PLUNICODE) 4 * hexpower ) ); 03708 *pfci = *pfci & mask; 03709 mask = ( ( (PLUNICODE) ( hexdigit & PL_FCI_HEXDIGIT_MASK ) ) << ( 4 * hexpower ) ); 03710 *pfci = *pfci | mask; 03711 } 03712 03713 /* Retrieve hex digit value from FCI that is masked out and shifted to the 03714 * right by hexpower hexadecimal digits. */ 03715 void 03716 plP_fci2hex( PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower ) 03717 { 03718 PLUNICODE mask; 03719 hexpower = hexpower & PL_FCI_HEXPOWER_MASK; 03720 mask = ( ( (PLUNICODE) PL_FCI_HEXPOWER_MASK ) << ( (PLUNICODE) ( 4 * hexpower ) ) ); 03721 *phexdigit = (unsigned char) ( ( fci & mask ) >> 03722 ( (PLUNICODE) ( 4 * hexpower ) ) ); 03723 } 03724 03725 /* Get the current library version number */ 03726 /* Note: you MUST have allocated space for this (80 characters is safe) */ 03727 void 03728 c_plgver( char *p_ver ) 03729 { 03730 strcpy( p_ver, VERSION ); 03731 } 03732 03733 /* Set inferior X window */ 03734 03735 void 03736 plsxwin( PLINT window_id ) 03737 { 03738 plsc->window_id = window_id; 03739 } 03740 03741 /*--------------------------------------------------------------------------*\ 03742 * These set/get information for family files, and may be called prior 03743 * to plinit to set up the necessary parameters. Arguments: 03744 * 03745 * fam familying flag (boolean) 03746 * num member number 03747 * bmax maximum member size 03748 \*--------------------------------------------------------------------------*/ 03749 03750 /* Get family file parameters */ 03751 03752 void 03753 c_plgfam( PLINT *p_fam, PLINT *p_num, PLINT *p_bmax ) 03754 { 03755 *p_fam = plsc->family; 03756 *p_num = plsc->member; 03757 *p_bmax = plsc->bytemax; 03758 } 03759 03760 /* Set family file parameters */ 03761 03762 void 03763 c_plsfam( PLINT fam, PLINT num, PLINT bmax ) 03764 { 03765 if ( plsc->level > 0 ) 03766 plwarn( "plsfam: Must be called before plinit." ); 03767 03768 if ( fam >= 0 ) 03769 plsc->family = fam; 03770 if ( num >= 0 ) 03771 plsc->member = num; 03772 if ( bmax >= 0 ) 03773 plsc->bytemax = bmax; 03774 } 03775 03776 /* Advance to the next family file on the next new page */ 03777 03778 void 03779 c_plfamadv( void ) 03780 { 03781 plsc->famadv = 1; 03782 } 03783 03784 /*--------------------------------------------------------------------------*\ 03785 * Interface routines for axis labling parameters. 03786 * See pldtik.c for more info. 03787 \*--------------------------------------------------------------------------*/ 03788 03789 /* Get x axis labeling parameters */ 03790 03791 void 03792 c_plgxax( PLINT *p_digmax, PLINT *p_digits ) 03793 { 03794 *p_digmax = plsc->xdigmax; 03795 *p_digits = plsc->xdigits; 03796 } 03797 03798 /* Set x axis labeling parameters */ 03799 03800 void 03801 c_plsxax( PLINT digmax, PLINT digits ) 03802 { 03803 plsc->xdigmax = digmax; 03804 plsc->xdigits = digits; 03805 } 03806 03807 /* Get y axis labeling parameters */ 03808 03809 void 03810 c_plgyax( PLINT *p_digmax, PLINT *p_digits ) 03811 { 03812 *p_digmax = plsc->ydigmax; 03813 *p_digits = plsc->ydigits; 03814 } 03815 03816 /* Set y axis labeling parameters */ 03817 03818 void 03819 c_plsyax( PLINT digmax, PLINT digits ) 03820 { 03821 plsc->ydigmax = digmax; 03822 plsc->ydigits = digits; 03823 } 03824 03825 /* Get z axis labeling parameters */ 03826 03827 void 03828 c_plgzax( PLINT *p_digmax, PLINT *p_digits ) 03829 { 03830 *p_digmax = plsc->zdigmax; 03831 *p_digits = plsc->zdigits; 03832 } 03833 03834 /* Set z axis labeling parameters */ 03835 03836 void 03837 c_plszax( PLINT digmax, PLINT digits ) 03838 { 03839 plsc->zdigmax = digmax; 03840 plsc->zdigits = digits; 03841 } 03842 03843 /* Get character default height and current (scaled) height */ 03844 03845 void 03846 c_plgchr( PLFLT *p_def, PLFLT *p_ht ) 03847 { 03848 *p_def = plsc->chrdef; 03849 *p_ht = plsc->chrht; 03850 } 03851 03852 /* Get viewport boundaries in normalized device coordinates */ 03853 03854 void 03855 c_plgvpd( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax ) 03856 { 03857 *p_xmin = plsc->vpdxmi; 03858 *p_xmax = plsc->vpdxma; 03859 *p_ymin = plsc->vpdymi; 03860 *p_ymax = plsc->vpdyma; 03861 } 03862 03863 /* Get viewport boundaries in world coordinates */ 03864 03865 void 03866 c_plgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax ) 03867 { 03868 *p_xmin = plsc->vpwxmi; 03869 *p_xmax = plsc->vpwxma; 03870 *p_ymin = plsc->vpwymi; 03871 *p_ymax = plsc->vpwyma; 03872 } 03873 03874 /* Get the viewport boundaries in world coordinates, expanded slightly */ 03875 void 03876 plP_xgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax ) 03877 { 03878 PLFLT dx, dy; 03879 03880 dx = ( plsc->vpwxma - plsc->vpwxmi ) * 1.0e-5; 03881 dy = ( plsc->vpwyma - plsc->vpwymi ) * 1.0e-5; 03882 03883 /* The plot window is made slightly larger than requested so that */ 03884 /* the end limits will be on the graph */ 03885 03886 *p_xmin = plsc->vpwxmi - dx; 03887 *p_xmax = plsc->vpwxma + dx; 03888 *p_ymin = plsc->vpwymi - dy; 03889 *p_ymax = plsc->vpwyma + dy; 03890 } 03891 03892 /*--------------------------------------------------------------------------*\ 03893 * These should not be called by the user. 03894 \*--------------------------------------------------------------------------*/ 03895 03896 /* Get x-y domain in world coordinates for 3d plots */ 03897 03898 void 03899 plP_gdom( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax ) 03900 { 03901 *p_xmin = plsc->domxmi; 03902 *p_xmax = plsc->domxma; 03903 *p_ymin = plsc->domymi; 03904 *p_ymax = plsc->domyma; 03905 } 03906 03907 /* Get vertical (z) scale parameters for 3-d plot */ 03908 03909 void 03910 plP_grange( PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax ) 03911 { 03912 *p_zscl = plsc->zzscl; 03913 *p_zmin = plsc->ranmi; 03914 *p_zmax = plsc->ranma; 03915 } 03916 03917 /* Get parameters used in 3d plots */ 03918 03919 void 03920 plP_gw3wc( PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz ) 03921 { 03922 *p_dxx = plsc->cxx; 03923 *p_dxy = plsc->cxy; 03924 *p_dyx = plsc->cyx; 03925 *p_dyy = plsc->cyy; 03926 *p_dyz = plsc->cyz; 03927 } 03928 03929 /* Get clip boundaries in physical coordinates */ 03930 03931 void 03932 plP_gclp( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax ) 03933 { 03934 *p_ixmin = plsc->clpxmi; 03935 *p_ixmax = plsc->clpxma; 03936 *p_iymin = plsc->clpymi; 03937 *p_iymax = plsc->clpyma; 03938 } 03939 03940 /* Set clip boundaries in physical coordinates */ 03941 03942 void 03943 plP_sclp( PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax ) 03944 { 03945 plsc->clpxmi = ixmin; 03946 plsc->clpxma = ixmax; 03947 plsc->clpymi = iymin; 03948 plsc->clpyma = iymax; 03949 } 03950 03951 /* Get physical device limits in physical coordinates */ 03952 03953 void 03954 plP_gphy( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax ) 03955 { 03956 *p_ixmin = plsc->phyxmi; 03957 *p_ixmax = plsc->phyxma; 03958 *p_iymin = plsc->phyymi; 03959 *p_iymax = plsc->phyyma; 03960 } 03961 03962 /* Get number of subpages on physical device and current subpage */ 03963 03964 void 03965 plP_gsub( PLINT *p_nx, PLINT *p_ny, PLINT *p_cs ) 03966 { 03967 *p_nx = plsc->nsubx; 03968 *p_ny = plsc->nsuby; 03969 *p_cs = plsc->cursub; 03970 } 03971 03972 /* Set number of subpages on physical device and current subpage */ 03973 03974 void 03975 plP_ssub( PLINT nx, PLINT ny, PLINT cs ) 03976 { 03977 plsc->nsubx = nx; 03978 plsc->nsuby = ny; 03979 plsc->cursub = cs; 03980 } 03981 03982 /* Get number of pixels to a millimeter */ 03983 03984 void 03985 plP_gpixmm( PLFLT *p_x, PLFLT *p_y ) 03986 { 03987 *p_x = plsc->xpmm; 03988 *p_y = plsc->ypmm; 03989 } 03990 03991 /* All the drivers call this to set physical pixels/mm. */ 03992 03993 void 03994 plP_setpxl( PLFLT xpmm, PLFLT ypmm ) 03995 { 03996 plsc->xpmm = xpmm; 03997 plsc->ypmm = ypmm; 03998 plsc->umx = (PLINT) ( 1000.0 / plsc->xpmm ); 03999 plsc->umy = (PLINT) ( 1000.0 / plsc->ypmm ); 04000 } 04001 04002 /* Sets up physical limits of plotting device. */ 04003 04004 void 04005 plP_setphy( PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax ) 04006 { 04007 if ( xmin > xmax || ymin > ymax ) 04008 plexit( "plP_setphy: device minima must not exceed maxima" ); 04009 04010 plsc->phyxmi = xmin; 04011 plsc->phyxma = xmax; 04012 plsc->phyymi = ymin; 04013 plsc->phyyma = ymax; 04014 plsc->phyxlen = xmax - xmin; 04015 plsc->phyylen = ymax - ymin; 04016 } 04017 04018 /*--------------------------------------------------------------------------*\ 04019 * void c_plscompression() 04020 * 04021 * Set compression. 04022 * Has to be done before plinit. 04023 \*--------------------------------------------------------------------------*/ 04024 04025 void 04026 c_plscompression( PLINT compression ) 04027 { 04028 if ( plsc->level <= 0 ) 04029 { 04030 plsc->dev_compression = compression; 04031 } 04032 } 04033 04034 /*--------------------------------------------------------------------------*\ 04035 * void c_plgcompression() 04036 * 04037 * Get compression 04038 \*--------------------------------------------------------------------------*/ 04039 04040 void 04041 c_plgcompression( PLINT *compression ) 04042 { 04043 *compression = plsc->dev_compression; 04044 } 04045 04046 04047 /*--------------------------------------------------------------------------*\ 04048 * void plP_getinitdriverlist() 04049 * 04050 * Check to see if a driver/stream has been initialised 04051 * Returns a space separated list of matches streams/drivers 04052 * If more than one stream uses the same device, then the device name 04053 * will be returned for each stream. 04054 * Caller must allocate enough memory for "names" to hold the answer. 04055 \*--------------------------------------------------------------------------*/ 04056 04057 void 04058 plP_getinitdriverlist( char *names ) 04059 { 04060 int i; 04061 04062 for ( i = 0; i < PL_NSTREAMS; ++i ) 04063 { 04064 if ( pls[i] != NULL ) 04065 { 04066 if ( i == 0 ) 04067 strcpy( names, pls[i]->DevName ); 04068 else 04069 { 04070 strcat( names, " " ); 04071 strcat( names, pls[i]->DevName ); 04072 } 04073 } 04074 else 04075 break; 04076 } 04077 } 04078 04079 04080 /*--------------------------------------------------------------------------*\ 04081 * PLINT plP_checkdriverinit() 04082 * 04083 * Checks from a list of given drivers which ones have been initialised 04084 * and returns the number of devices matching the list, or -1 if in error. 04085 * Effectively returns the number of streams matching the given stream. 04086 \*--------------------------------------------------------------------------*/ 04087 04088 PLINT plP_checkdriverinit( char *names ) 04089 { 04090 char *buff; 04091 char *tok = NULL; 04092 PLINT ret = 0; /* set up return code to 0, the value if no devices match*/ 04093 04094 buff = (char *) malloc( (size_t) PL_NSTREAMS * 8 ); /* Allocate enough memory for 8 04095 * characters for each possible stream */ 04096 04097 if ( buff != NULL ) 04098 { 04099 memset( buff, 0, PL_NSTREAMS * 8 ); /* Make sure we clear it */ 04100 plP_getinitdriverlist( buff ); /* Get the list of initialised devices */ 04101 04102 for ( tok = strtok( buff, " ," ); /* Check each device against the "name" */ 04103 tok; tok = strtok( 0, " ," ) ) /* supplied to the subroutine */ 04104 { 04105 if ( strstr( names, tok ) != NULL ) /* Check to see if the device has been initialised */ 04106 { 04107 ret++; /* Bump the return code if it has */ 04108 } 04109 } 04110 free( buff ); /* Clear up that memory we allocated */ 04111 } 04112 else 04113 ret = -1; /* Error flag */ 04114 04115 return ( ret ); 04116 } 04117 04118 04119 /*--------------------------------------------------------------------------*\ 04120 * plP_image 04121 * 04122 * Author: Alessandro Mirone, Nov 2001 04123 * 04124 * Updated by Hezekiah Carty, Mar 2008. 04125 * - Added support for pltr callback 04126 * - Commented out the "dev_fastimg" rendering path 04127 * 04128 \*--------------------------------------------------------------------------*/ 04129 04130 void 04131 plP_image( PLFLT *z, PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT dy, 04132 void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ), PLPointer pltr_data ) 04133 { 04134 plsc->page_status = DRAWING; 04135 04136 plimageslow( z, nx, ny, xmin, ymin, dx, dy, pltr, pltr_data ); 04137 04138 /* 04139 * COMMENTED OUT by Hezekiah Carty, March 2008 04140 * The current dev_fastimg rendering method does not work as-is with 04141 * the plimagefr coordinate transform support. 04142 * This is hopefully temporary, until the dev_fastimg rendering 04143 * path can be updated to work with the new plimage internals. 04144 * Until then, all plimage* rendering is done by the plimageslow 04145 * rendering path. 04146 */ 04147 #if 0 /* BEGIN dev_fastimg COMMENT */ 04148 PLINT i, npts; 04149 short *xscl, *yscl; 04150 int plbuf_write; 04151 04152 plsc->page_status = DRAWING; 04153 04154 if ( plsc->dev_fastimg == 0 ) 04155 { 04156 plimageslow( x, y, z, nx - 1, ny - 1, 04157 xmin, ymin, dx, dy, zmin, zmax ); 04158 return; 04159 } 04160 04161 if ( plsc->plbuf_write ) 04162 { 04163 IMG_DT img_dt; 04164 04165 img_dt.xmin = xmin; 04166 img_dt.ymin = ymin; 04167 img_dt.dx = dx; 04168 img_dt.dy = dy; 04169 04170 plsc->dev_ix = x; 04171 plsc->dev_iy = y; 04172 plsc->dev_z = z; 04173 plsc->dev_nptsX = nx; 04174 plsc->dev_nptsY = ny; 04175 plsc->dev_zmin = zmin; 04176 plsc->dev_zmax = zmax; 04177 04178 plbuf_esc( plsc, PLESC_IMAGE, &img_dt ); 04179 } 04180 04181 /* avoid re-saving plot buffer while in plP_esc() */ 04182 plbuf_write = plsc->plbuf_write; 04183 plsc->plbuf_write = 0; 04184 04185 npts = nx * ny; 04186 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) */ 04187 { 04188 PLINT clpxmi, clpxma, clpymi, clpyma; 04189 04190 if ( ( ( xscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) || 04191 ( ( yscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) ) 04192 { 04193 plexit( "plP_image: Insufficient memory" ); 04194 } 04195 04196 for ( i = 0; i < npts; i++ ) 04197 { 04198 xscl[i] = x[i]; 04199 yscl[i] = y[i]; 04200 } 04201 sdifilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma ); 04202 plsc->imclxmin = clpxmi; 04203 plsc->imclymin = clpymi; 04204 plsc->imclxmax = clpxma; 04205 plsc->imclymax = clpyma; 04206 grimage( xscl, yscl, z, nx, ny ); 04207 free( xscl ); 04208 free( yscl ); 04209 } 04210 else 04211 { 04212 plsc->imclxmin = plsc->phyxmi; 04213 plsc->imclymin = plsc->phyymi; 04214 plsc->imclxmax = plsc->phyxma; 04215 plsc->imclymax = plsc->phyyma; 04216 grimage( x, y, z, nx, ny ); 04217 } 04218 plsc->plbuf_write = plbuf_write; 04219 #endif /* END dev_fastimg COMMENT */ 04220 } 04221 04222 /*--------------------------------------------------------------------------*\ 04223 * plstransform 04224 * 04225 * Set a universal coordinate transform function which will be applied to all 04226 * plotted items. 04227 \*--------------------------------------------------------------------------*/ 04228 void 04229 c_plstransform( void ( *coordinate_transform )( PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer ), PLPointer coordinate_transform_data ) 04230 { 04231 plsc->coordinate_transform = coordinate_transform; 04232 plsc->coordinate_transform_data = coordinate_transform_data; 04233 }