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