PLplot 5.9.6
|
00001 /* $Id$ 00002 * 00003 * Misc. control routines, like begin, end, exit, change graphics/text 00004 * mode, change color. Includes some spillage from plcore.c. If you 00005 * don't know where it should go, put it here. 00006 * 00007 * Copyright (C) 2004 Joao Cardoso 00008 * Copyright (C) 2004 Rafael Laboissiere 00009 * Copyright (C) 2008 Hazen Babcock 00010 * Copyright (C) 2009 Alan W. Irwin 00011 * 00012 * This file is part of PLplot. 00013 * 00014 * PLplot is free software; you can redistribute it and/or modify 00015 * it under the terms of the GNU General Library Public License as published 00016 * by the Free Software Foundation; either version 2 of the License, or 00017 * (at your option) any later version. 00018 * 00019 * PLplot is distributed in the hope that it will be useful, 00020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 * GNU Library General Public License for more details. 00023 * 00024 * You should have received a copy of the GNU Library General Public License 00025 * along with PLplot; if not, write to the Free Software 00026 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00027 * 00028 */ 00029 00030 #define DEBUG 00031 00032 #define NEED_PLDEBUG 00033 #include "plplotP.h" 00034 #ifdef macintosh 00035 #include "mac.h" 00036 /* for plMacLibOpen prototype; used in plLibOpen */ 00037 #endif 00038 00039 #ifdef DJGPP /* dos386/djgpp */ 00040 #ifdef __unix 00041 #undef __unix 00042 #endif 00043 #endif 00044 00045 #ifdef __unix 00046 #include <sys/types.h> 00047 #include <sys/stat.h> 00048 #ifdef PL_HAVE_UNISTD_H 00049 #include <unistd.h> 00050 #endif 00051 #include <errno.h> 00052 #endif 00053 00054 /* Random number generator (Mersenne Twister) */ 00055 #include "mt19937ar.h" 00056 00057 #define BUFFER_SIZE 256 00058 00059 /* small epsilon for fuzzy range checks that is still large enough to 00060 * work even in the single precision floating point case.*/ 00061 #define FUZZ_EPSILON 1.e-4 00062 00063 /* Static functions */ 00064 00065 /* Used by any external init code to suggest a path */ 00066 char PLDLLIMPEXP * plplotLibDir = 0; 00067 00068 static void 00069 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, char *name ); 00070 00071 static void 00072 strcat_delim( char *dirspec ); 00073 00074 static int 00075 ( *exit_handler )( const char *errormsg ); 00076 00077 static void 00078 ( *abort_handler )( const char *errormsg ); 00079 00080 static void 00081 plcmap0_def( int imin, int imax ); 00082 00083 static void 00084 plcmap1_def( void ); 00085 00086 static PLFLT 00087 value( double n1, double n2, double hue ); 00088 00089 static void 00090 cmap0_palette_read( const char *filename, 00091 int *number_colors, int **r, int **g, int **b, double **a ); 00092 /* An additional hardwired location for lib files. */ 00093 /* I have no plans to change these again, ever. */ 00094 00095 #if defined ( DJGPP ) 00096 #ifndef PLLIBDEV 00097 #define PLLIBDEV "c:/plplot/lib" 00098 #endif 00099 00100 #elif defined ( MSDOS ) 00101 #ifndef PLLIBDEV 00102 #define PLLIBDEV "c:\\plplot\\lib" 00103 #endif 00104 00105 #else 00106 00107 /* Anything else is assumed to be Unix */ 00108 00109 #ifndef PLLIBDEV 00110 #define PLLIBDEV "/usr/local/plplot/lib" 00111 #endif 00112 00113 #endif 00114 00115 /*--------------------------------------------------------------------------*\ 00116 * Routines that deal with colors & color maps. 00117 \*--------------------------------------------------------------------------*/ 00118 00119 /*--------------------------------------------------------------------------*\ 00120 * plcol0() 00121 * 00122 * Set color, map 0. Argument is integer between 0 and plsc->ncol0. 00123 \*--------------------------------------------------------------------------*/ 00124 00125 void 00126 c_plcol0( PLINT icol0 ) 00127 { 00128 if ( plsc->level < 1 ) 00129 { 00130 plabort( "plcol0: Please call plinit first" ); 00131 return; 00132 } 00133 if ( icol0 < 0 || icol0 >= plsc->ncol0 ) 00134 { 00135 char buffer[BUFFER_SIZE]; 00136 snprintf( buffer, BUFFER_SIZE, "plcol0: Invalid color map entry: %d", (int) icol0 ); 00137 plabort( buffer ); 00138 return; 00139 } 00140 00141 plsc->icol0 = icol0; 00142 plsc->curcolor.r = plsc->cmap0[icol0].r; 00143 plsc->curcolor.g = plsc->cmap0[icol0].g; 00144 plsc->curcolor.b = plsc->cmap0[icol0].b; 00145 plsc->curcolor.a = plsc->cmap0[icol0].a; 00146 00147 plsc->curcmap = 0; 00148 plP_state( PLSTATE_COLOR0 ); 00149 } 00150 00151 /*--------------------------------------------------------------------------*\ 00152 * plcol1() 00153 * 00154 * Set color, map 1. Argument is a float between 0. and 1. 00155 \*--------------------------------------------------------------------------*/ 00156 00157 void 00158 c_plcol1( PLFLT col1 ) 00159 { 00160 PLINT icol1; 00161 00162 if ( plsc->level < 1 ) 00163 { 00164 plabort( "plcol1: Please call plinit first" ); 00165 return; 00166 } 00167 if ( col1 < 0 || col1 > 1 || isnan( col1 ) ) 00168 { 00169 char buffer[BUFFER_SIZE]; 00170 snprintf( buffer, BUFFER_SIZE, "plcol1: Invalid color map position: %f", (PLFLT) col1 ); 00171 plabort( buffer ); 00172 return; 00173 } 00174 00175 icol1 = (PLINT) ( col1 * plsc->ncol1 ); 00176 icol1 = MIN( icol1, plsc->ncol1 - 1 ); 00177 00178 plsc->icol1 = icol1; 00179 plsc->curcolor.r = plsc->cmap1[plsc->icol1].r; 00180 plsc->curcolor.g = plsc->cmap1[plsc->icol1].g; 00181 plsc->curcolor.b = plsc->cmap1[plsc->icol1].b; 00182 plsc->curcolor.a = plsc->cmap1[plsc->icol1].a; 00183 00184 plsc->curcmap = 1; 00185 plP_state( PLSTATE_COLOR1 ); 00186 } 00187 00188 /*--------------------------------------------------------------------------*\ 00189 * plscolbg() 00190 * 00191 * Set the background color (cmap0[0]) by 8 bit RGB value 00192 \*--------------------------------------------------------------------------*/ 00193 00194 void 00195 c_plscolbg( PLINT r, PLINT g, PLINT b ) 00196 { 00197 plscol0( 0, r, g, b ); 00198 } 00199 00200 /*--------------------------------------------------------------------------*\ 00201 * plscolbga() 00202 * 00203 * Set the background color (cmap0[0]) by 8 bit RGB value and alpha value 00204 \*--------------------------------------------------------------------------*/ 00205 00206 void 00207 c_plscolbga( PLINT r, PLINT g, PLINT b, PLFLT a ) 00208 { 00209 plscol0a( 0, r, g, b, a ); 00210 } 00211 00212 /*--------------------------------------------------------------------------*\ 00213 * plgcolbg() 00214 * 00215 * Returns the background color (cmap0[0]) by 8 bit RGB value 00216 \*--------------------------------------------------------------------------*/ 00217 00218 void 00219 c_plgcolbg( PLINT *r, PLINT *g, PLINT *b ) 00220 { 00221 plgcol0( 0, r, g, b ); 00222 } 00223 00224 /*--------------------------------------------------------------------------*\ 00225 * plgcolbga() 00226 * 00227 * Returns the background color (cmap0[0]) by 8 bit RGB value and alpha value 00228 \*--------------------------------------------------------------------------*/ 00229 00230 void 00231 c_plgcolbga( PLINT *r, PLINT *g, PLINT *b, PLFLT *a ) 00232 { 00233 plgcol0a( 0, r, g, b, a ); 00234 } 00235 00236 /*--------------------------------------------------------------------------*\ 00237 * plscol0() 00238 * 00239 * Set a given color from color map 0 by 8 bit RGB value 00240 * Does not result in any additional cells to be allocated. 00241 \*--------------------------------------------------------------------------*/ 00242 00243 void 00244 c_plscol0( PLINT icol0, PLINT r, PLINT g, PLINT b ) 00245 { 00246 if ( plsc->cmap0 == NULL ) 00247 plscmap0n( 0 ); 00248 if ( icol0 < 0 || icol0 >= plsc->ncol0 ) 00249 { 00250 char buffer[BUFFER_SIZE]; 00251 snprintf( buffer, BUFFER_SIZE, "plscol0: Illegal color table value: %d", (int) icol0 ); 00252 plabort( buffer ); 00253 return; 00254 } 00255 if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) ) 00256 { 00257 char buffer[BUFFER_SIZE]; 00258 snprintf( buffer, BUFFER_SIZE, "plscol0: Invalid RGB color: %d, %d, %d", 00259 (int) r, (int) g, (int) b ); 00260 plabort( buffer ); 00261 return; 00262 } 00263 00264 plscol0a( icol0, r, g, b, 1.0 ); 00265 } 00266 00267 /*--------------------------------------------------------------------------*\ 00268 * plscol0a() 00269 * 00270 * Set a given color from color map 0 by 8 bit RGB value and alpha value. 00271 * Does not result in any additional cells to be allocated. 00272 \*--------------------------------------------------------------------------*/ 00273 00274 void 00275 c_plscol0a( PLINT icol0, PLINT r, PLINT g, PLINT b, PLFLT a ) 00276 { 00277 if ( plsc->cmap0 == NULL ) 00278 plscmap0n( 0 ); 00279 if ( icol0 < 0 || icol0 >= plsc->ncol0 ) 00280 { 00281 char buffer[BUFFER_SIZE]; 00282 snprintf( buffer, BUFFER_SIZE, "plscol0a: Illegal color table value: %d", (int) icol0 ); 00283 plabort( buffer ); 00284 return; 00285 } 00286 if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) || ( a < 0 || a > 1.0 ) ) 00287 { 00288 char buffer[BUFFER_SIZE]; 00289 snprintf( buffer, BUFFER_SIZE, "plscol0a: Invalid RGB color: %d, %d, %d, %f", 00290 (int) r, (int) g, (int) b, (double) a ); 00291 plabort( buffer ); 00292 return; 00293 } 00294 00295 plsc->cmap0[icol0].r = r; 00296 plsc->cmap0[icol0].g = g; 00297 plsc->cmap0[icol0].b = b; 00298 plsc->cmap0[icol0].a = a; 00299 00300 if ( plsc->level > 0 ) 00301 plP_state( PLSTATE_CMAP0 ); 00302 } 00303 00304 /*--------------------------------------------------------------------------*\ 00305 * plgcol0() 00306 * 00307 * Returns 8 bit RGB values for given color from color map 0 00308 * Values are negative if an invalid color id is given 00309 \*--------------------------------------------------------------------------*/ 00310 00311 void 00312 c_plgcol0( PLINT icol0, PLINT *r, PLINT *g, PLINT *b ) 00313 { 00314 if ( plsc->cmap0 == NULL ) 00315 plscmap0n( 0 ); 00316 00317 *r = -1; 00318 *g = -1; 00319 *b = -1; 00320 00321 if ( icol0 < 0 || icol0 > plsc->ncol0 ) 00322 { 00323 char buffer[BUFFER_SIZE]; 00324 snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 ); 00325 plabort( buffer ); 00326 return; 00327 } 00328 00329 *r = plsc->cmap0[icol0].r; 00330 *g = plsc->cmap0[icol0].g; 00331 *b = plsc->cmap0[icol0].b; 00332 00333 return; 00334 } 00335 00336 /*--------------------------------------------------------------------------*\ 00337 * plgcol0a() 00338 * 00339 * Returns 8 bit RGB values for given color from color map 0 and alpha value 00340 * Values are negative if an invalid color id is given 00341 \*--------------------------------------------------------------------------*/ 00342 00343 void 00344 c_plgcol0a( PLINT icol0, PLINT *r, PLINT *g, PLINT *b, PLFLT *a ) 00345 { 00346 if ( plsc->cmap0 == NULL ) 00347 plscmap0n( 0 ); 00348 00349 *r = -1; 00350 *g = -1; 00351 *b = -1; 00352 *a = -1.0; 00353 00354 if ( icol0 < 0 || icol0 > plsc->ncol0 ) 00355 { 00356 char buffer[BUFFER_SIZE]; 00357 snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 ); 00358 plabort( buffer ); 00359 return; 00360 } 00361 00362 *r = plsc->cmap0[icol0].r; 00363 *g = plsc->cmap0[icol0].g; 00364 *b = plsc->cmap0[icol0].b; 00365 *a = plsc->cmap0[icol0].a; 00366 00367 return; 00368 } 00369 00370 /*--------------------------------------------------------------------------*\ 00371 * plscmap0() 00372 * 00373 * Set color map 0 colors by 8 bit RGB values. This sets the entire color 00374 * map -- only as many colors as specified will be allocated. 00375 \*--------------------------------------------------------------------------*/ 00376 00377 void 00378 c_plscmap0( PLINT *r, PLINT *g, PLINT *b, PLINT ncol0 ) 00379 { 00380 int i; 00381 00382 plscmap0n( ncol0 ); 00383 00384 for ( i = 0; i < plsc->ncol0; i++ ) 00385 { 00386 if ( ( r[i] < 0 || r[i] > 255 ) || 00387 ( g[i] < 0 || g[i] > 255 ) || 00388 ( b[i] < 0 || b[i] > 255 ) ) 00389 { 00390 char buffer[BUFFER_SIZE]; 00391 snprintf( buffer, BUFFER_SIZE, "plscmap0: Invalid RGB color: %d, %d, %d", 00392 (int) r[i], (int) g[i], (int) b[i] ); 00393 plabort( buffer ); 00394 return; 00395 } 00396 00397 plsc->cmap0[i].r = r[i]; 00398 plsc->cmap0[i].g = g[i]; 00399 plsc->cmap0[i].b = b[i]; 00400 plsc->cmap0[i].a = 1.0; 00401 } 00402 00403 if ( plsc->level > 0 ) 00404 plP_state( PLSTATE_CMAP0 ); 00405 } 00406 00407 /*--------------------------------------------------------------------------*\ 00408 * plscmap0a() 00409 * 00410 * Set color map 0 colors by 8 bit RGB and alpha value. This sets the 00411 * entire color map -- only as many colors as specified will be allocated. 00412 \*--------------------------------------------------------------------------*/ 00413 00414 void 00415 c_plscmap0a( PLINT *r, PLINT *g, PLINT *b, PLFLT *a, PLINT ncol0 ) 00416 { 00417 int i; 00418 00419 plscmap0n( ncol0 ); 00420 00421 for ( i = 0; i < plsc->ncol0; i++ ) 00422 { 00423 if ( ( r[i] < 0 || r[i] > 255 ) || 00424 ( g[i] < 0 || g[i] > 255 ) || 00425 ( b[i] < 0 || b[i] > 255 ) || 00426 ( a[i] < 0.0 || a[i] > 1.0 ) ) 00427 { 00428 char buffer[BUFFER_SIZE]; 00429 snprintf( buffer, BUFFER_SIZE, "plscmap0a: Invalid RGB color: %d, %d, %d, %f", 00430 (int) r[i], (int) g[i], (int) b[i], (double) a[i] ); 00431 plabort( buffer ); 00432 return; 00433 } 00434 00435 plsc->cmap0[i].r = r[i]; 00436 plsc->cmap0[i].g = g[i]; 00437 plsc->cmap0[i].b = b[i]; 00438 plsc->cmap0[i].a = a[i]; 00439 } 00440 00441 if ( plsc->level > 0 ) 00442 plP_state( PLSTATE_CMAP0 ); 00443 } 00444 00445 /*--------------------------------------------------------------------------*\ 00446 * plscmap1() 00447 * 00448 * Set color map 1 colors by 8 bit RGB values 00449 * This also sets the number of colors. 00450 \*--------------------------------------------------------------------------*/ 00451 00452 void 00453 c_plscmap1( PLINT *r, PLINT *g, PLINT *b, PLINT ncol1 ) 00454 { 00455 int i; 00456 00457 plscmap1n( ncol1 ); 00458 00459 for ( i = 0; i < plsc->ncol1; i++ ) 00460 { 00461 if ( ( r[i] < 0 || r[i] > 255 ) || 00462 ( g[i] < 0 || g[i] > 255 ) || 00463 ( b[i] < 0 || b[i] > 255 ) ) 00464 { 00465 char buffer[BUFFER_SIZE]; 00466 snprintf( buffer, BUFFER_SIZE, "plscmap1: Invalid RGB color: %d, %d, %d", 00467 (int) r[i], (int) g[i], (int) b[i] ); 00468 plabort( buffer ); 00469 return; 00470 } 00471 plsc->cmap1[i].r = r[i]; 00472 plsc->cmap1[i].g = g[i]; 00473 plsc->cmap1[i].b = b[i]; 00474 plsc->cmap1[i].a = 1.0; 00475 } 00476 00477 if ( plsc->level > 0 ) 00478 plP_state( PLSTATE_CMAP1 ); 00479 } 00480 00481 /*--------------------------------------------------------------------------*\ 00482 * plscmap1a() 00483 * 00484 * Set color map 1 colors by 8 bit RGB and alpha values 00485 * This also sets the number of colors. 00486 \*--------------------------------------------------------------------------*/ 00487 00488 void 00489 c_plscmap1a( PLINT *r, PLINT *g, PLINT *b, PLFLT *a, PLINT ncol1 ) 00490 { 00491 int i; 00492 00493 plscmap1n( ncol1 ); 00494 00495 for ( i = 0; i < plsc->ncol1; i++ ) 00496 { 00497 if ( ( r[i] < 0 || r[i] > 255 ) || 00498 ( g[i] < 0 || g[i] > 255 ) || 00499 ( b[i] < 0 || b[i] > 255 ) || 00500 ( a[i] < 0.0 || a[i] > 1.0 ) ) 00501 { 00502 char buffer[BUFFER_SIZE]; 00503 snprintf( buffer, BUFFER_SIZE, "plscmap1a: Invalid RGB color: %d, %d, %d, %f", 00504 (int) r[i], (int) g[i], (int) b[i], (double) a[i] ); 00505 plabort( buffer ); 00506 return; 00507 } 00508 plsc->cmap1[i].r = r[i]; 00509 plsc->cmap1[i].g = g[i]; 00510 plsc->cmap1[i].b = b[i]; 00511 plsc->cmap1[i].a = a[i]; 00512 } 00513 00514 if ( plsc->level > 0 ) 00515 plP_state( PLSTATE_CMAP1 ); 00516 } 00517 00518 /*--------------------------------------------------------------------------*\ 00519 * plscmap1l() 00520 * 00521 * Set color map 1 colors using a piece-wise linear relationship between 00522 * position in the color map (from 0 to 1) and position in HLS or RGB color 00523 * space. May be called at any time. 00524 * 00525 * The idea here is to specify a number of control points that specify the 00526 * mapping between HLS (or RGB or CMY) and palette 1 value. Between these 00527 * points, linear interpolation is used. By mapping position in the color 00528 * map to function value, this gives a smooth variation of color with 00529 * intensity. Any number of control points may be specified, located at 00530 * arbitrary positions (intensities), although typically 2 - 4 are enough. 00531 * Another way of stating this is that we are traversing a given number of 00532 * lines through HLS (or RGB) space as we move through cmap 1 entries. The 00533 * control points at the minimum and maximum intensity (0 and 1) must 00534 * always be specified. By adding more control points you can get more 00535 * variation. One good technique for plotting functions that vary about 00536 * some expected average is to use an additional 2 control points in the 00537 * center (intensity ~= 0.5) that are the same color as the background 00538 * (typically white for paper output, black for crt), and same hue as the 00539 * boundary control points. This allows the highs and lows to be very 00540 * easily distinguished. 00541 * 00542 * Each control point must specify the position in cmap 1 as well as three 00543 * coordinates in HLS or RGB space. The first point MUST correspond to 00544 * position = 0, and the last to position = 1. 00545 * 00546 * The hue is interpolated around the "front" of the color wheel 00547 * (red<->green<->blue<->red) unless the "rev" flag is set, in which case 00548 * interpolation proceeds around the back (reverse) side. Specifying 00549 * rev=NULL is equivalent to setting rev[]=0 for every control point. 00550 * 00551 * Bounds on RGB coordinates: 00552 * R,G,B [0, 1] magnitude 00553 * 00554 * Bounds on HLS coordinates: 00555 * hue [0, 360] degrees 00556 * lightness [0, 1] magnitude 00557 * saturation [0, 1] magnitude 00558 * 00559 * The inputs are: 00560 * itype 0: HLS, 1: RGB 00561 * npts number of control points 00562 * pos[] position for each control point 00563 * coord1[] first coordinate for each control point 00564 * coord2[] second coordinate for each control point 00565 * coord3[] third coordinate for each control point 00566 * rev[] reverse flag for each control point 00567 \*--------------------------------------------------------------------------*/ 00568 00569 void 00570 c_plscmap1l( PLINT itype, PLINT npts, PLFLT *pos, 00571 PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLINT *rev ) 00572 { 00573 int n; 00574 PLFLT h, l, s, r, g, b; 00575 00576 if ( npts < 2 ) 00577 { 00578 plabort( "plscmap1l: Must specify at least two control points" ); 00579 return; 00580 } 00581 00582 if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) ) 00583 { 00584 plabort( "plscmap1l: First, last control points must lie on boundary" ); 00585 return; 00586 } 00587 00588 if ( npts > PL_MAX_CMAP1CP ) 00589 { 00590 plabort( "plscmap1l: exceeded maximum number of control points" ); 00591 return; 00592 } 00593 00594 /* Allocate if not done yet */ 00595 00596 if ( plsc->cmap1 == NULL ) 00597 plscmap1n( 0 ); 00598 00599 /* Save control points */ 00600 00601 plsc->ncp1 = npts; 00602 00603 for ( n = 0; n < npts; n++ ) 00604 { 00605 if ( itype == 0 ) 00606 { 00607 h = coord1[n]; 00608 l = coord2[n]; 00609 s = coord3[n]; 00610 } 00611 else 00612 { 00613 r = coord1[n]; 00614 g = coord2[n]; 00615 b = coord3[n]; 00616 c_plrgbhls( r, g, b, &h, &l, &s ); 00617 } 00618 00619 plsc->cmap1cp[n].h = h; 00620 plsc->cmap1cp[n].l = l; 00621 plsc->cmap1cp[n].s = s; 00622 plsc->cmap1cp[n].p = pos[n]; 00623 plsc->cmap1cp[n].a = 1.0; 00624 00625 if ( rev == NULL ) 00626 plsc->cmap1cp[n].rev = 0; 00627 else 00628 plsc->cmap1cp[n].rev = rev[n]; 00629 } 00630 00631 /* Calculate and set color map */ 00632 00633 plcmap1_calc(); 00634 } 00635 00636 /*--------------------------------------------------------------------------*\ 00637 * plscmap1la() 00638 * 00639 * This is the same as plscmap1l, but also allows alpha value interpolation. 00640 * 00641 \*-------------------------------------------------------------------------*/ 00642 00643 void 00644 c_plscmap1la( PLINT itype, PLINT npts, PLFLT *pos, 00645 PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLFLT *a, PLINT *rev ) 00646 { 00647 int n; 00648 PLFLT h, l, s, r, g, b; 00649 00650 if ( npts < 2 ) 00651 { 00652 plabort( "plscmap1la: Must specify at least two control points" ); 00653 return; 00654 } 00655 00656 if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) ) 00657 { 00658 plabort( "plscmap1la: First, last control points must lie on boundary" ); 00659 return; 00660 } 00661 00662 if ( npts > PL_MAX_CMAP1CP ) 00663 { 00664 plabort( "plscmap1la: exceeded maximum number of control points" ); 00665 return; 00666 } 00667 00668 /* Allocate if not done yet */ 00669 00670 if ( plsc->cmap1 == NULL ) 00671 plscmap1n( 0 ); 00672 00673 /* Save control points */ 00674 00675 plsc->ncp1 = npts; 00676 00677 for ( n = 0; n < npts; n++ ) 00678 { 00679 if ( itype == 0 ) 00680 { 00681 h = coord1[n]; 00682 l = coord2[n]; 00683 s = coord3[n]; 00684 } 00685 else 00686 { 00687 r = coord1[n]; 00688 g = coord2[n]; 00689 b = coord3[n]; 00690 c_plrgbhls( r, g, b, &h, &l, &s ); 00691 } 00692 00693 plsc->cmap1cp[n].h = h; 00694 plsc->cmap1cp[n].l = l; 00695 plsc->cmap1cp[n].s = s; 00696 plsc->cmap1cp[n].p = pos[n]; 00697 plsc->cmap1cp[n].a = a[n]; 00698 00699 if ( rev == NULL ) 00700 plsc->cmap1cp[n].rev = 0; 00701 else 00702 plsc->cmap1cp[n].rev = rev[n]; 00703 } 00704 00705 /* Calculate and set color map */ 00706 00707 plcmap1_calc(); 00708 } 00709 00710 /*--------------------------------------------------------------------------*\ 00711 * plcmap1_calc() 00712 * 00713 * Bin up cmap 1 space and assign colors to make inverse mapping easy. 00714 * Always do interpolation in HLS space. 00715 \*--------------------------------------------------------------------------*/ 00716 00717 void 00718 plcmap1_calc( void ) 00719 { 00720 int i, n; 00721 PLFLT delta, dp, dh, dl, ds, da; 00722 PLFLT h, l, s, p, r, g, b, a; 00723 00724 /* Loop over all control point pairs */ 00725 00726 for ( n = 0; n < plsc->ncp1 - 1; n++ ) 00727 { 00728 if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n + 1].p ) 00729 continue; 00730 00731 /* Differences in p, h, l, s between ctrl pts */ 00732 00733 dp = plsc->cmap1cp[n + 1].p - plsc->cmap1cp[n].p; 00734 dh = plsc->cmap1cp[n + 1].h - plsc->cmap1cp[n].h; 00735 dl = plsc->cmap1cp[n + 1].l - plsc->cmap1cp[n].l; 00736 ds = plsc->cmap1cp[n + 1].s - plsc->cmap1cp[n].s; 00737 da = plsc->cmap1cp[n + 1].a - plsc->cmap1cp[n].a; 00738 00739 /* Adjust dh if we are to go around "the back side" */ 00740 00741 if ( plsc->cmap1cp[n].rev ) 00742 dh = ( dh > 0 ) ? dh - 360 : dh + 360; 00743 00744 /* Loop over all color cells. Only interested in cells located (in */ 00745 /* cmap1 space) between n_th and n+1_th control points */ 00746 00747 for ( i = 0; i < plsc->ncol1; i++ ) 00748 { 00749 p = (double) i / ( plsc->ncol1 - 1.0 ); 00750 if ( ( p < plsc->cmap1cp[n].p ) || 00751 ( p > plsc->cmap1cp[n + 1].p ) ) 00752 continue; 00753 00754 /* Interpolate based on position of color cell in cmap1 space */ 00755 00756 delta = ( p - plsc->cmap1cp[n].p ) / dp; 00757 00758 /* Linearly interpolate to get color cell h, l, s values */ 00759 00760 h = plsc->cmap1cp[n].h + dh * delta; 00761 l = plsc->cmap1cp[n].l + dl * delta; 00762 s = plsc->cmap1cp[n].s + ds * delta; 00763 a = plsc->cmap1cp[n].a + da * delta; 00764 00765 while ( h >= 360. ) 00766 h -= 360.; 00767 00768 while ( h < 0. ) 00769 h += 360.; 00770 00771 c_plhlsrgb( h, l, s, &r, &g, &b ); 00772 00773 plsc->cmap1[i].r = MAX( 0, MIN( 255, (int) ( 256. * r ) ) ); 00774 plsc->cmap1[i].g = MAX( 0, MIN( 255, (int) ( 256. * g ) ) ); 00775 plsc->cmap1[i].b = MAX( 0, MIN( 255, (int) ( 256. * b ) ) ); 00776 plsc->cmap1[i].a = a; 00777 } 00778 } 00779 00780 if ( plsc->level > 0 ) 00781 plP_state( PLSTATE_CMAP1 ); 00782 } 00783 00784 /*--------------------------------------------------------------------------*\ 00785 * plscmap0n() 00786 * 00787 * Set number of colors in cmap 0, (re-)allocate cmap 0, and fill with 00788 * default values for those colors not previously allocated (and less 00789 * than index 15, after that you just get grey). 00790 * 00791 * The driver is not guaranteed to support all of these. 00792 \*--------------------------------------------------------------------------*/ 00793 00794 void 00795 c_plscmap0n( PLINT ncol0 ) 00796 { 00797 int ncol, size, imin, imax; 00798 00799 /* No change */ 00800 00801 if ( ncol0 > 0 && plsc->ncol0 == ncol0 ) 00802 return; 00803 00804 /* Handle all possible startup conditions */ 00805 00806 if ( plsc->ncol0 <= 0 && ncol0 <= 0 ) 00807 ncol = 16; 00808 else if ( ncol0 <= 0 ) 00809 ncol = plsc->ncol0; 00810 else 00811 ncol = ncol0; 00812 00813 imax = ncol - 1; 00814 size = ncol * sizeof ( PLColor ); 00815 00816 /* Allocate the space */ 00817 00818 if ( plsc->cmap0 == NULL ) 00819 { 00820 if ( ( plsc->cmap0 = (PLColor *) calloc( 1, size ) ) == NULL ) 00821 { 00822 plexit( "c_plscmap0n: Insufficient memory" ); 00823 } 00824 imin = 0; 00825 } 00826 else 00827 { 00828 if ( ( plsc->cmap0 = (PLColor *) realloc( plsc->cmap0, size ) ) == NULL ) 00829 { 00830 plexit( "c_plscmap0n: Insufficient memory" ); 00831 } 00832 imin = plsc->ncol0; 00833 } 00834 00835 /* Fill in default entries */ 00836 00837 plsc->ncol0 = ncol; 00838 plcmap0_def( imin, imax ); 00839 00840 if ( plsc->level > 0 ) 00841 plP_state( PLSTATE_CMAP0 ); 00842 } 00843 00844 /*--------------------------------------------------------------------------*\ 00845 * color_set() 00846 * 00847 * Initializes color table entry by RGB values. 00848 \*--------------------------------------------------------------------------*/ 00849 00850 void 00851 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, char *name ) 00852 { 00853 plsc->cmap0[i].r = r; 00854 plsc->cmap0[i].g = g; 00855 plsc->cmap0[i].b = b; 00856 plsc->cmap0[i].a = a; 00857 plsc->cmap0[i].name = name; 00858 } 00859 00860 #define color_def( i, r, g, b, a, n ) \ 00861 if ( i >= imin && i <= imax ) color_set( i, r, g, b, a, n ); 00862 00863 /*--------------------------------------------------------------------------*\ 00864 * plcmap0_def() 00865 * 00866 * Initializes specified color map 0 color entry to its default for 00867 * index range from imin to imax. 00868 \*--------------------------------------------------------------------------*/ 00869 00870 void 00871 plcmap0_def( int imin, int imax ) 00872 { 00873 int i, *r, *g, *b; 00874 double *a; 00875 int number_colors; 00876 if ( imin <= imax ) 00877 { 00878 cmap0_palette_read( "", &number_colors, &r, &g, &b, &a ); 00879 for ( i = imin; i <= MIN( ( number_colors - 1 ), imax ); i++ ) 00880 color_def( i, r[i], g[i], b[i], a[i], 00881 "colors defined by default cmap0 palette file" ); 00882 free( r ); 00883 free( g ); 00884 free( b ); 00885 free( a ); 00886 } 00887 else 00888 { 00889 number_colors = 0; 00890 } 00891 00892 /* Initialize all colours undefined by the default colour palette file 00893 * to opaque red as a warning. */ 00894 for ( i = MAX( number_colors, imin ); i <= imax; i++ ) 00895 color_def( i, 255, 0, 0, 1.0, 00896 "opaque red colour to mark not defined by palette file" ); 00897 } 00898 00899 /*--------------------------------------------------------------------------*\ 00900 * plscmap1n() 00901 * 00902 * Set number of colors in cmap 1, (re-)allocate cmap 1, and set default 00903 * values if this is the first allocation. 00904 * 00905 * Note that the driver is allowed to disregard this number. 00906 * In particular, most use fewer than we use internally. 00907 \*--------------------------------------------------------------------------*/ 00908 00909 void 00910 c_plscmap1n( PLINT ncol1 ) 00911 { 00912 int ncol, size; 00913 00914 /* No change */ 00915 00916 if ( ncol1 > 0 && plsc->ncol1 == ncol1 ) 00917 return; 00918 00919 /* Handle all possible startup conditions */ 00920 00921 if ( plsc->ncol1 <= 0 && ncol1 <= 0 ) 00922 ncol = 128; 00923 else if ( ncol1 <= 0 ) 00924 ncol = plsc->ncol1; 00925 else 00926 ncol = ncol1; 00927 00928 size = ncol * sizeof ( PLColor ); 00929 00930 /* Allocate the space */ 00931 00932 if ( plsc->ncol1 > 0 ) 00933 { 00934 if ( ( plsc->cmap1 = (PLColor *) realloc( plsc->cmap1, size ) ) == NULL ) 00935 { 00936 plexit( "c_plscmap1n: Insufficient memory" ); 00937 } 00938 } 00939 else 00940 { 00941 if ( ( plsc->cmap1 = (PLColor *) calloc( ncol, sizeof ( PLColor ) ) ) == NULL ) 00942 { 00943 plexit( "c_plscmap1n: Insufficient memory" ); 00944 } 00945 } 00946 00947 /* Fill in default entries */ 00948 00949 plsc->ncol1 = ncol; 00950 if ( plsc->ncp1 == 0 ) 00951 plcmap1_def(); 00952 else 00953 plcmap1_calc(); 00954 } 00955 00956 /*--------------------------------------------------------------------------*\ 00957 * plcmap1_def() 00958 * 00959 * Initializes color map 1. 00960 * 00961 * The default initialization uses 6 control points in HLS space, the inner 00962 * ones being very close to one of the vertices of the HLS double cone. The 00963 * vertex used (black or white) is chosen to be the closer to the background 00964 * color. The 6 points were chosen over the older 4 points in order to make 00965 * weaker structures more easily visible, and give more control through the 00966 * palette editor. If you don't like these settings.. change them! 00967 \*--------------------------------------------------------------------------*/ 00968 00969 void 00970 plcmap1_def( void ) 00971 { 00972 PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.; 00973 00974 /* Positions of control points */ 00975 00976 i[0] = 0; /* left boundary */ 00977 i[1] = 0.44; /* a little left of center */ 00978 i[2] = 0.50; /* at center */ 00979 i[3] = 0.50; /* at center */ 00980 i[4] = 0.56; /* a little right of center */ 00981 i[5] = 1; /* right boundary */ 00982 00983 /* For center control points, pick black or white, whichever is closer to bg */ 00984 /* Be careful to pick just short of top or bottom else hue info is lost */ 00985 00986 if ( plsc->cmap0 != NULL ) 00987 vertex = ( (PLFLT) plsc->cmap0[0].r + 00988 (PLFLT) plsc->cmap0[0].g + 00989 (PLFLT) plsc->cmap0[0].b ) / 3. / 255.; 00990 00991 if ( vertex < 0.5 ) 00992 { 00993 vertex = 0.01; 00994 midpt = 0.10; 00995 } 00996 else 00997 { 00998 vertex = 0.99; 00999 midpt = 0.90; 01000 } 01001 01002 /* Set hue */ 01003 01004 h[0] = 260; /* low: blue-violet */ 01005 h[1] = 260; /* only change as we go over vertex */ 01006 h[2] = 260; /* only change as we go over vertex */ 01007 h[3] = 0; /* high: red */ 01008 h[4] = 0; /* high: red */ 01009 h[5] = 0; /* keep fixed */ 01010 01011 /* Set lightness */ 01012 01013 l[0] = 0.5; /* low */ 01014 l[1] = midpt; /* midpoint value */ 01015 l[2] = vertex; /* bg */ 01016 l[3] = vertex; /* bg */ 01017 l[4] = midpt; /* midpoint value */ 01018 l[5] = 0.5; /* high */ 01019 01020 /* Set saturation -- keep at maximum */ 01021 01022 s[0] = 1; 01023 s[1] = 1; 01024 s[2] = 1; 01025 s[3] = 1; 01026 s[4] = 1; 01027 s[5] = 1; 01028 01029 c_plscmap1l( 0, 6, i, h, l, s, NULL ); 01030 01031 if ( plsc->level > 0 ) 01032 plP_state( PLSTATE_CMAP1 ); 01033 } 01034 01035 /*--------------------------------------------------------------------------*\ 01036 * plscolor() 01037 * 01038 * Used to globally turn color output on/off 01039 \*--------------------------------------------------------------------------*/ 01040 01041 void 01042 c_plscolor( PLINT color ) 01043 { 01044 plsc->colorset = 1; 01045 plsc->color = color; 01046 } 01047 01048 /*--------------------------------------------------------------------------*\ 01049 * plrgb() 01050 * 01051 * Set line color by red, green, blue from 0. to 1. 01052 * Do NOT use this. Only retained for backward compatibility 01053 \*--------------------------------------------------------------------------*/ 01054 01055 void 01056 c_plrgb( PLFLT r, PLFLT g, PLFLT b ) 01057 { 01058 if ( plsc->level < 1 ) 01059 { 01060 plabort( "plrgb: Please call plinit first" ); 01061 return; 01062 } 01063 01064 plsc->icol0 = PL_RGB_COLOR; 01065 plsc->curcolor.r = MAX( 0, MIN( 255, (int) ( 256. * r ) ) ); 01066 plsc->curcolor.g = MAX( 0, MIN( 255, (int) ( 256. * g ) ) ); 01067 plsc->curcolor.b = MAX( 0, MIN( 255, (int) ( 256. * b ) ) ); 01068 01069 plsc->curcmap = 0; 01070 plP_state( PLSTATE_COLOR0 ); 01071 } 01072 01073 /*--------------------------------------------------------------------------*\ 01074 * plrgb1() 01075 * 01076 * Set line color by 8 bit RGB values. 01077 * Do NOT use this. Only retained for backward compatibility 01078 \*--------------------------------------------------------------------------*/ 01079 01080 void 01081 c_plrgb1( PLINT r, PLINT g, PLINT b ) 01082 { 01083 if ( plsc->level < 1 ) 01084 { 01085 plabort( "plrgb1: Please call plinit first" ); 01086 return; 01087 } 01088 if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) ) 01089 { 01090 plabort( "plrgb1: Invalid color" ); 01091 return; 01092 } 01093 01094 plsc->icol0 = PL_RGB_COLOR; 01095 plsc->curcolor.r = r; 01096 plsc->curcolor.g = g; 01097 plsc->curcolor.b = b; 01098 01099 plsc->curcmap = 0; 01100 plP_state( PLSTATE_COLOR0 ); 01101 } 01102 01103 /*--------------------------------------------------------------------------*\ 01104 * void plhls() 01105 * 01106 * Set current color by hue, lightness, and saturation. 01107 * Convert hls color coordinates to rgb, then call plrgb. 01108 * Do NOT use this. Only retained for backward compatibility 01109 \*--------------------------------------------------------------------------*/ 01110 01111 void 01112 c_plhls( PLFLT h, PLFLT l, PLFLT s ) 01113 { 01114 PLFLT r, g, b; 01115 01116 c_plhlsrgb( h, l, s, &r, &g, &b ); 01117 plrgb( r, g, b ); 01118 } 01119 01120 /*--------------------------------------------------------------------------*\ 01121 * void value() 01122 * 01123 * Auxiliary function used by c_plhlsrgb(). 01124 \*--------------------------------------------------------------------------*/ 01125 01126 PLFLT 01127 value( double n1, double n2, double hue ) 01128 { 01129 PLFLT val; 01130 01131 while ( hue >= 360. ) 01132 hue -= 360.; 01133 while ( hue < 0. ) 01134 hue += 360.; 01135 01136 if ( hue < 60. ) 01137 val = n1 + ( n2 - n1 ) * hue / 60.; 01138 else if ( hue < 180. ) 01139 val = n2; 01140 else if ( hue < 240. ) 01141 val = n1 + ( n2 - n1 ) * ( 240. - hue ) / 60.; 01142 else 01143 val = n1; 01144 01145 return ( val ); 01146 } 01147 01148 /*--------------------------------------------------------------------------*\ 01149 * void c_plhlsrgb() 01150 * 01151 * Convert HLS color to RGB color. 01152 * Bounds on HLS (input): 01153 * hue [0., 360.] degrees 01154 * lightness [0., 1.] magnitude 01155 * saturation [0., 1.] magnitude 01156 * 01157 * Hue is always mapped onto the interval [0., 360.] regardless of input. 01158 * Bounds on RGB (output) is always [0., 1.]. Convert to RGB color values 01159 * by multiplying by 2**nbits (nbits typically 8). 01160 \*--------------------------------------------------------------------------*/ 01161 01162 void 01163 c_plhlsrgb( PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b ) 01164 { 01165 PLFLT m1, m2; 01166 01167 if ( l <= .5 ) 01168 m2 = l * ( s + 1. ); 01169 else 01170 m2 = l + s - l * s; 01171 01172 m1 = 2 * l - m2; 01173 01174 *p_r = value( m1, m2, h + 120. ); 01175 *p_g = value( m1, m2, h ); 01176 *p_b = value( m1, m2, h - 120. ); 01177 } 01178 01179 /*--------------------------------------------------------------------------*\ 01180 * void c_plrgbhls() 01181 * 01182 * Convert RGB color to HLS color. 01183 * Bounds on RGB (input) is always [0., 1.]. 01184 * Bounds on HLS (output): 01185 * hue [0., 360.] degrees 01186 * lightness [0., 1.] magnitude 01187 * saturation [0., 1.] magnitude 01188 \*--------------------------------------------------------------------------*/ 01189 01190 void 01191 c_plrgbhls( PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s ) 01192 { 01193 PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max; 01194 01195 rgb_min = MIN( r, MIN( g, b ) ); 01196 rgb_max = MAX( r, MAX( g, b ) ); 01197 01198 l = ( rgb_min + rgb_max ) / 2.0; 01199 01200 if ( rgb_min == rgb_max ) 01201 { 01202 s = 0; 01203 h = 0; 01204 } 01205 else 01206 { 01207 d = rgb_max - rgb_min; 01208 if ( l < 0.5 ) 01209 s = 0.5 * d / l; 01210 else 01211 s = 0.5 * d / ( 1. - l ); 01212 01213 rc = ( rgb_max - r ) / d; 01214 gc = ( rgb_max - g ) / d; 01215 bc = ( rgb_max - b ) / d; 01216 01217 if ( r == rgb_max ) 01218 h = bc - gc; 01219 else if ( g == rgb_max ) 01220 h = rc - bc + 2; 01221 else 01222 h = gc - rc - 2; 01223 01224 h = h * 60; 01225 if ( h < 0 ) 01226 h = h + 360; 01227 else if ( h >= 360 ) 01228 h = h - 360; 01229 } 01230 *p_h = h; 01231 *p_l = l; 01232 *p_s = s; 01233 } 01234 01235 /*--------------------------------------------------------------------------*\ 01236 * cmap0_palette_read() 01237 * 01238 * Read and check r, g, b, a data from a cmap0*.pal format file. 01239 * The caller must free the returned malloc'ed space for r, g, b, and a. 01240 \*--------------------------------------------------------------------------*/ 01241 01242 void 01243 cmap0_palette_read( const char *filename, 01244 int *number_colors, int **r, int **g, int **b, double **a ) 01245 { 01246 int i, err = 0; 01247 char color_info[30]; 01248 char msgbuf[1024]; 01249 FILE *fp; 01250 char * save_locale = plsave_set_locale(); 01251 01252 if ( strlen( filename ) == 0 ) 01253 { 01254 fp = plLibOpen( PL_DEFAULT_CMAP0_FILE ); 01255 if ( fp == NULL ) 01256 { 01257 snprintf( msgbuf, 1024, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE ); 01258 plwarn( msgbuf ); 01259 err = 1; 01260 } 01261 } 01262 else 01263 { 01264 fp = plLibOpen( filename ); 01265 if ( fp == NULL ) 01266 { 01267 snprintf( msgbuf, 1024, "Unable to open cmap0 file %s\n", filename ); 01268 plwarn( msgbuf ); 01269 err = 1; 01270 } 01271 } 01272 if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) ) 01273 { 01274 fclose( fp ); 01275 snprintf( msgbuf, 1024, "Unrecognized cmap0 header\n" ); 01276 plwarn( msgbuf ); 01277 err = 1; 01278 } 01279 01280 if ( !err ) 01281 { 01282 /* Allocate arrays to hold r, g, b, and a data for calling routine. 01283 * The caller must free these after it is finished with them. */ 01284 if ( ( ( *r = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01285 ( ( *g = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01286 ( ( *b = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01287 ( ( *a = (double *) malloc( *number_colors * sizeof ( double ) ) ) == NULL ) ) 01288 { 01289 fclose( fp ); 01290 plexit( "cmap0_palette_read: insufficient memory" ); 01291 } 01292 01293 for ( i = 0; i < *number_colors; i++ ) 01294 { 01295 if ( fgets( color_info, 30, fp ) == NULL ) 01296 { 01297 err = 1; 01298 break; 01299 } 01300 color_info[strlen( color_info ) - 1] = '\0'; /* remove return character */ 01301 if ( strlen( color_info ) == 7 ) 01302 { 01303 if ( sscanf( color_info, "#%2x%2x%2x", 01304 (int *) ( *r + i ), (int *) ( *g + i ), (int *) ( *b + i ) ) != 3 ) 01305 { 01306 err = 1; 01307 break; 01308 } 01309 *( *a + i ) = 1.0; 01310 } 01311 else if ( strlen( color_info ) > 9 ) 01312 { 01313 if ( sscanf( color_info, "#%2x%2x%2x %lf", 01314 (int *) ( *r + i ), (int *) ( *g + i ), (int *) ( *b + i ), 01315 (double *) ( *a + i ) ) != 4 ) 01316 { 01317 err = 1; 01318 break; 01319 } 01320 /* fuzzy range check. */ 01321 if ( *( *a + i ) < -FUZZ_EPSILON || *( *a + i ) > ( 1. + FUZZ_EPSILON ) ) 01322 { 01323 err = 1; 01324 break; 01325 } 01326 else if ( *( *a + i ) < 0. ) 01327 { 01328 *( *a + i ) = 0.; 01329 } 01330 else if ( *( *a + i ) > 1. ) 01331 { 01332 *( *a + i ) = 1.; 01333 } 01334 } 01335 else 01336 { 01337 err = 1; 01338 break; 01339 } 01340 } 01341 fclose( fp ); 01342 if ( err ) 01343 { 01344 snprintf( msgbuf, 1024, "Unrecognized cmap0 format data line. Line is %s\n", 01345 color_info ); 01346 plwarn( msgbuf ); 01347 free( *r ); 01348 free( *g ); 01349 free( *b ); 01350 free( *a ); 01351 } 01352 } 01353 /* Fall back to opaque red on opaque white as visual warning of any 01354 * error above. */ 01355 if ( err ) 01356 { 01357 *number_colors = 16; 01358 if ( ( ( *r = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01359 ( ( *g = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01360 ( ( *b = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) || 01361 ( ( *a = (double *) malloc( *number_colors * sizeof ( double ) ) ) == NULL ) ) 01362 { 01363 plexit( "cmap0_palette_read: insufficient memory" ); 01364 } 01365 **r = 255; 01366 **g = 255; 01367 **b = 255; 01368 **a = 1.; 01369 for ( i = 1; i < *number_colors; i++ ) 01370 { 01371 *( *r + i ) = 255; 01372 *( *g + i ) = 0; 01373 *( *b + i ) = 0; 01374 *( *a + i ) = 1.0; 01375 } 01376 } 01377 01378 plrestore_locale( save_locale ); 01379 } 01380 01381 /*--------------------------------------------------------------------------*\ 01382 * void c_plspal0(filename) 01383 * 01384 * Set the palette for color map 0 using a cmap0*.pal format file. 01385 * filename: the name of the cmap0*.pal file to use. 01386 \*--------------------------------------------------------------------------*/ 01387 01388 void 01389 c_plspal0( const char *filename ) 01390 { 01391 int i, *r, *g, *b; 01392 double *a; 01393 int number_colors; 01394 cmap0_palette_read( filename, &number_colors, &r, &g, &b, &a ); 01395 /* Allocate default number of cmap0 colours if cmap0 allocation not 01396 * done already. */ 01397 plscmap0n( 0 ); 01398 /* Allocate sufficient cmap0 colours to contain present data. */ 01399 if ( number_colors > plsc->ncol0 ) 01400 { 01401 plscmap0n( number_colors ); 01402 } 01403 for ( i = 0; i < number_colors; i++ ) 01404 { 01405 c_plscol0a( i, r[i], g[i], b[i], a[i] ); 01406 } 01407 free( r ); 01408 free( g ); 01409 free( b ); 01410 free( a ); 01411 } 01412 01413 /* This code fragment used a lot in plspal1 to deal with 01414 * floating-point range checking of a value and the adjustment of that 01415 * value when close to the range when there is floating-point errors. 01416 */ 01417 #define fuzzy_range_check( value, min, max, fuzz, err_number ) \ 01418 if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) { \ 01419 snprintf( msgbuf, 1024, "Unrecognized cmap1 format data line. Error number is %d. Line is %s\n", err_number, color_info ); \ 01420 plwarn( msgbuf ); \ 01421 err = 1; \ 01422 break; \ 01423 } else if ( value < min ) { \ 01424 value = min; \ 01425 } else if ( value > max ) { \ 01426 value = max; \ 01427 } 01428 /*--------------------------------------------------------------------------*\ 01429 * void c_plspal1(filename) 01430 * 01431 * Set the palette for color map 1 using a cmap1*.pal format file. 01432 * filename: the name of the cmap1*.pal file to use. 01433 \*--------------------------------------------------------------------------*/ 01434 01435 void 01436 c_plspal1( const char *filename, PLBOOL interpolate ) 01437 { 01438 int i; 01439 int number_colors; 01440 int format_version, err; 01441 PLBOOL rgb; 01442 char color_info[160]; 01443 int r_i, g_i, b_i, pos_i, rev_i; 01444 double r_d, g_d, b_d, a_d, pos_d; 01445 PLFLT *r, *g, *b, *a, *pos; 01446 PLINT *ri, *gi, *bi; 01447 PLBOOL *rev; 01448 FILE *fp; 01449 char msgbuf[1024]; 01450 char * save_locale = plsave_set_locale(); 01451 01452 rgb = TRUE; 01453 err = 0; 01454 format_version = 0; 01455 if ( strlen( filename ) == 0 ) 01456 { 01457 fp = plLibOpen( PL_DEFAULT_CMAP1_FILE ); 01458 if ( fp == NULL ) 01459 { 01460 snprintf( msgbuf, 1024, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE ); 01461 plwarn( msgbuf ); 01462 goto finish; 01463 } 01464 } 01465 else 01466 { 01467 fp = plLibOpen( filename ); 01468 if ( fp == NULL ) 01469 { 01470 snprintf( msgbuf, 1024, "Unable to open cmap1 .pal file %s\n", filename ); 01471 plwarn( msgbuf ); 01472 goto finish; 01473 } 01474 } 01475 /* Check for new file format */ 01476 if ( fgets( color_info, 160, fp ) == NULL ) 01477 { 01478 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename ); 01479 plwarn( msgbuf ); 01480 fclose( fp ); 01481 goto finish; 01482 } 01483 if ( strncmp( color_info, "v2 ", 2 ) == 0 ) 01484 { 01485 format_version = 1; 01486 if ( strncmp( &color_info[3], "hls", 3 ) == 0 ) 01487 rgb = FALSE; 01488 else if ( strncmp( &color_info[3], "rgb", 3 ) == 0 ) 01489 rgb = TRUE; 01490 else 01491 { 01492 snprintf( msgbuf, 1024, "Invalid color space %s - assuming RGB\n", &color_info[3] ); 01493 plwarn( msgbuf ); 01494 rgb = TRUE; 01495 } 01496 if ( fgets( color_info, 160, fp ) == NULL ) 01497 { 01498 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename ); 01499 plwarn( msgbuf ); 01500 fclose( fp ); 01501 goto finish; 01502 } 01503 } 01504 01505 if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 ) 01506 { 01507 snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info ); 01508 plwarn( msgbuf ); 01509 fclose( fp ); 01510 goto finish; 01511 } 01512 01513 r = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01514 g = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01515 b = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01516 ri = (PLINT *) malloc( number_colors * sizeof ( PLINT ) ); 01517 gi = (PLINT *) malloc( number_colors * sizeof ( PLINT ) ); 01518 bi = (PLINT *) malloc( number_colors * sizeof ( PLINT ) ); 01519 a = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01520 pos = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01521 rev = (PLBOOL *) malloc( number_colors * sizeof ( PLBOOL ) ); 01522 01523 if ( format_version == 0 ) 01524 { 01525 int return_sscanf, return_sscanf_old = 0; 01526 /* Old tk file format */ 01527 for ( i = 0; i < number_colors; i++ ) 01528 { 01529 if ( fgets( color_info, 160, fp ) == NULL ) 01530 { 01531 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename ); 01532 plwarn( msgbuf ); 01533 fclose( fp ); 01534 goto finish; 01535 } 01536 /* Ensure string is null terminated if > 160 characters */ 01537 color_info[159] = '\0'; 01538 return_sscanf = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &rev_i ); 01539 if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) ) 01540 { 01541 snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info ); 01542 plwarn( msgbuf ); 01543 err = 1; 01544 break; 01545 } 01546 return_sscanf_old = return_sscanf; 01547 /* For old format, input colours range from 0 to 255 and 01548 * need to be renormalized to the range from 0. to 1.. */ 01549 r[i] = (PLFLT) r_i / 255.; 01550 g[i] = (PLFLT) g_i / 255.; 01551 b[i] = (PLFLT) b_i / 255.; 01552 a[i] = 1.0; 01553 pos[i] = 0.01 * (PLFLT) pos_i; 01554 fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 1 ); 01555 fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 2 ); 01556 fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 3 ); 01557 fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 4 ); 01558 if ( return_sscanf == 5 ) 01559 { 01560 /* Next to oldest tk format with rev specified. */ 01561 rev[i] = (PLBOOL) rev_i; 01562 } 01563 } 01564 if ( return_sscanf == 4 ) 01565 { 01566 /* Oldest tk format. No rev specified. */ 01567 free( rev ); 01568 rev = NULL; 01569 } 01570 } 01571 else 01572 { 01573 /* New floating point file version with support for alpha and rev values */ 01574 for ( i = 0; i < number_colors; i++ ) 01575 { 01576 if ( fgets( color_info, 160, fp ) == NULL ) 01577 { 01578 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename ); 01579 plwarn( msgbuf ); 01580 fclose( fp ); 01581 goto finish; 01582 } 01583 if ( sscanf( color_info, "%lf %lf %lf %lf %lf %d", &pos_d, &r_d, &g_d, &b_d, &a_d, &rev_i ) != 6 ) 01584 { 01585 snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info ); 01586 plwarn( msgbuf ); 01587 err = 1; 01588 break; 01589 } 01590 01591 r[i] = (PLFLT) r_d; 01592 g[i] = (PLFLT) g_d; 01593 b[i] = (PLFLT) b_d; 01594 a[i] = (PLFLT) a_d; 01595 pos[i] = (PLFLT) pos_d; 01596 /* Check that all rgba and pos data within range from 0. to 01597 * 1. except for the hls colour space case where the first 01598 * coordinate is checked within range from 0. to 360.*/ 01599 if ( rgb ) 01600 { 01601 fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 5 ); 01602 } 01603 else 01604 { 01605 fuzzy_range_check( r[i], 0., 360., ( 360. * FUZZ_EPSILON ), 6 ); 01606 } 01607 fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 7 ); 01608 fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 8 ); 01609 fuzzy_range_check( a[i], 0., 1., FUZZ_EPSILON, 9 ); 01610 fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 10 ); 01611 01612 rev[i] = (PLBOOL) rev_i; 01613 } 01614 } 01615 fclose( fp ); 01616 01617 if ( !err ) 01618 { 01619 if ( interpolate ) 01620 { 01621 c_plscmap1la( rgb, number_colors, pos, r, g, b, a, rev ); 01622 } 01623 else 01624 { 01625 for ( i = 0; i < number_colors; i++ ) 01626 { 01627 ri[i] = r[i] * 255.0; 01628 gi[i] = g[i] * 255.0; 01629 bi[i] = b[i] * 255.0; 01630 } 01631 c_plscmap1a( ri, gi, bi, a, number_colors ); 01632 } 01633 } 01634 else 01635 { 01636 /* Fall back to red scale as visual warning if some problem occurred 01637 * above. */ 01638 free( r ); 01639 free( g ); 01640 free( b ); 01641 free( pos ); 01642 number_colors = 2; 01643 r = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01644 g = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01645 b = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01646 pos = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) ); 01647 r[0] = 0.; 01648 r[1] = 1.; 01649 g[0] = 0.; 01650 g[1] = 0.; 01651 b[0] = 0.; 01652 b[1] = 0.; 01653 pos[0] = 0.; 01654 pos[1] = 1.; 01655 c_plscmap1l( TRUE, number_colors, pos, r, g, b, NULL ); 01656 } 01657 01658 free( r ); 01659 free( g ); 01660 free( b ); 01661 free( ri ); 01662 free( gi ); 01663 free( bi ); 01664 free( a ); 01665 free( pos ); 01666 free( rev ); 01667 01668 finish: plrestore_locale( save_locale ); 01669 } 01670 01671 /*--------------------------------------------------------------------------*\ 01672 * A grab-bag of various control routines. 01673 \*--------------------------------------------------------------------------*/ 01674 01675 /*--------------------------------------------------------------------------*\ 01676 * void plwarn() 01677 * 01678 * A handy way to issue warnings, if need be. 01679 \*--------------------------------------------------------------------------*/ 01680 01681 void 01682 plwarn( const char *errormsg ) 01683 { 01684 int was_gfx = 0; 01685 01686 if ( plsc->graphx == 1 ) 01687 { 01688 was_gfx = 1; 01689 pltext(); 01690 } 01691 01692 fprintf( stderr, "\n*** PLPLOT WARNING ***\n" ); 01693 if ( *errormsg != '\0' ) 01694 fprintf( stderr, "%s\n", errormsg ); 01695 01696 if ( was_gfx == 1 ) 01697 plgra(); 01698 } 01699 01700 /*--------------------------------------------------------------------------*\ 01701 * void plabort() 01702 * 01703 * Much the same as plwarn(), but appends ", aborting operation" to the 01704 * error message. Helps to keep source code uncluttered and provides a 01705 * convention for error aborts. 01706 * 01707 * If cleanup needs to be done in the main program, the user should write 01708 * his/her own exit handler and pass it in via plsabort(). 01709 \*--------------------------------------------------------------------------*/ 01710 01711 void 01712 plabort( const char *errormsg ) 01713 { 01714 if ( abort_handler != NULL ) 01715 ( *abort_handler )( errormsg ); 01716 01717 if ( plsc->errcode != NULL ) 01718 *( plsc->errcode ) = 1; 01719 01720 if ( plsc->errmsg != NULL ) 01721 { 01722 sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" ); 01723 if ( *errormsg != '\0' ) 01724 sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg ); 01725 } 01726 else 01727 { 01728 int was_gfx = 0; 01729 01730 if ( plsc->graphx == 1 ) 01731 { 01732 was_gfx = 1; 01733 pltext(); 01734 } 01735 01736 fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" ); 01737 if ( *errormsg != '\0' ) 01738 fprintf( stderr, "%s, aborting operation\n", errormsg ); 01739 01740 if ( was_gfx == 1 ) 01741 plgra(); 01742 } 01743 } 01744 01745 01746 /*--------------------------------------------------------------------------*\ 01747 * void plsabort() 01748 * 01749 * Sets an optional user abort handler. 01750 \*--------------------------------------------------------------------------*/ 01751 01752 void 01753 plsabort( void ( *handler )( const char * ) ) 01754 { 01755 abort_handler = handler; 01756 } 01757 01758 /*--------------------------------------------------------------------------*\ 01759 * void plexit() 01760 * 01761 * In case of an abort this routine is called. It just prints out an error 01762 * message and tries to clean up as much as possible. It's best to turn 01763 * off pause and then restore previous setting before returning. 01764 * 01765 * If cleanup needs to be done in the main program, the user should write 01766 * his/her own exit handler and pass it in via plsexit(). This function 01767 * should should either call plend() before exiting, or simply return. 01768 \*--------------------------------------------------------------------------*/ 01769 01770 void 01771 plexit( const char *errormsg ) 01772 { 01773 int status = 1; 01774 01775 if ( exit_handler != NULL ) 01776 status = ( *exit_handler )( errormsg ); 01777 01778 plsc->nopause = 1; 01779 if ( *errormsg != '\0' ) 01780 { 01781 fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" ); 01782 fprintf( stderr, "%s\n", errormsg ); 01783 } 01784 plend(); 01785 01786 fprintf( stderr, "Program aborted\n" ); 01787 exit( status ); 01788 } 01789 01790 /*--------------------------------------------------------------------------*\ 01791 * void plsexit() 01792 * 01793 * Sets an optional user exit handler. 01794 \*--------------------------------------------------------------------------*/ 01795 01796 void 01797 plsexit( int ( *handler )( const char * ) ) 01798 { 01799 exit_handler = handler; 01800 } 01801 01802 /*--------------------------------------------------------------------------*\ 01803 * void plgra() 01804 * 01805 * Switches to graphics screen. 01806 * 01807 * Here and in pltext() it's a good idea to return silently if plinit() 01808 * hasn't yet been called, since plwarn() calls pltext() and plgra(), and 01809 * plwarn() may be called at any time. 01810 \*--------------------------------------------------------------------------*/ 01811 01812 void 01813 c_plgra( void ) 01814 { 01815 if ( plsc->level > 0 ) 01816 plP_esc( PLESC_GRAPH, NULL ); 01817 } 01818 01819 void 01820 c_plxormod( PLINT mode, PLINT *status ) /* xor mode */ 01821 { 01822 static int ostate = 0; 01823 01824 if ( !plsc->dev_xor ) 01825 { 01826 *status = 0; 01827 return; 01828 } 01829 01830 if ( plsc->level > 0 ) 01831 { 01832 plP_esc( PLESC_XORMOD, &mode ); 01833 if ( mode ) 01834 { 01835 ostate = plsc->plbuf_write; 01836 plsc->plbuf_write = 0; 01837 } 01838 else 01839 plsc->plbuf_write = ostate; 01840 } 01841 *status = 1; 01842 } 01843 01844 /*--------------------------------------------------------------------------*\ 01845 * void pltext() 01846 * 01847 * Switches to text screen. 01848 \*--------------------------------------------------------------------------*/ 01849 01850 void 01851 c_pltext( void ) 01852 { 01853 if ( plsc->level > 0 ) 01854 plP_esc( PLESC_TEXT, NULL ); 01855 } 01856 01857 /*--------------------------------------------------------------------------*\ 01858 * void pl_cmd() 01859 * 01860 * Front-end to driver escape function. 01861 * In principle this can be used to pass just about anything directly 01862 * to the driver. 01863 \*--------------------------------------------------------------------------*/ 01864 01865 void 01866 pl_cmd( PLINT op, void *ptr ) 01867 { 01868 plP_esc( op, ptr ); 01869 } 01870 01871 /*--------------------------------------------------------------------------*\ 01872 * char *plFindCommand 01873 * 01874 * Looks for the specified executable file. Search path: 01875 * if command invoked in the build tree: 01876 * build_tree/tk (plserver lies there - needed for the tk driver) 01877 * source_tree/scripts (plpr lies there - needed for the tk driver) 01878 * else 01879 * PLPLOT_BIN_ENV = $(PLPLOT_BIN) 01880 * current directory 01881 * PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin 01882 * BIN_DIR 01883 * 01884 * The caller must free the returned pointer (points to malloc'ed memory) 01885 * when finished with it. 01886 \*--------------------------------------------------------------------------*/ 01887 01888 char * 01889 plFindCommand( const char *fn ) 01890 { 01891 char *fs = NULL, *dn; 01892 01893 /**** see if in build tree ***/ 01894 if ( plInBuildTree() == 1 ) 01895 { 01896 plGetName( BUILD_DIR, "bindings/tk", fn, &fs ); 01897 if ( !plFindName( fs ) ) 01898 return fs; 01899 else 01900 { 01901 plGetName( SOURCE_DIR, "scripts", fn, &fs ); 01902 if ( !plFindName( fs ) ) 01903 return fs; 01904 } 01905 } 01906 01907 /* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */ 01908 01909 #if defined ( PLPLOT_BIN_ENV ) 01910 if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL ) 01911 { 01912 plGetName( dn, "", fn, &fs ); 01913 if ( !plFindName( fs ) ) 01914 return fs; 01915 fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); /* what IS set? */ 01916 } 01917 #endif /* PLPLOT_BIN_ENV */ 01918 01919 /* Current directory */ 01920 01921 plGetName( ".", "", fn, &fs ); 01922 if ( !plFindName( fs ) ) 01923 return fs; 01924 01925 /* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */ 01926 01927 #if defined ( PLPLOT_HOME_ENV ) 01928 if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL ) 01929 { 01930 plGetName( dn, "bin", fn, &fs ); 01931 if ( !plFindName( fs ) ) 01932 return fs; 01933 fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); /* what IS set? */ 01934 } 01935 #endif /* PLPLOT_HOME_ENV */ 01936 01937 /* BIN_DIR */ 01938 01939 #if defined ( BIN_DIR ) 01940 plGetName( BIN_DIR, "", fn, &fs ); 01941 if ( !plFindName( fs ) ) 01942 return fs; 01943 #endif 01944 01945 /* Crapped out */ 01946 01947 free_mem( fs ); 01948 fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn ); 01949 #if defined ( BIN_DIR ) 01950 fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" ); /* what WAS set? */ 01951 #endif /* BIN_DIR */ 01952 return NULL; 01953 } 01954 01955 /*--------------------------------------------------------------------------*\ 01956 * FILE *plLibOpen(fn) 01957 * 01958 * Return file pointer to lib file. 01959 * Locations checked: 01960 * PLPLOT_LIB_ENV = $(PLPLOT_LIB) 01961 * current directory 01962 * PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib 01963 * DATA_DIR 01964 * PLLIBDEV 01965 \*--------------------------------------------------------------------------*/ 01966 01967 FILE * 01968 plLibOpen( const char *fn ) 01969 { 01970 FILE *ret = NULL; 01971 01972 PDFstrm *pdfs = plLibOpenPdfstrm( fn ); 01973 if ( pdfs == NULL ) 01974 { 01975 return NULL; 01976 } 01977 if ( pdfs->file != NULL ) 01978 { 01979 ret = pdfs->file; 01980 pdfs->file = NULL; 01981 } 01982 pdf_close( pdfs ); 01983 return ret; 01984 } 01985 01986 PDFstrm * 01987 plLibOpenPdfstrm( const char *fn ) 01988 { 01989 PDFstrm *file; 01990 char *fs = NULL, *dn = NULL; 01991 01992 /**** search build tree ****/ 01993 01994 if ( plInBuildTree() == 1 ) 01995 { 01996 plGetName( SOURCE_DIR, "data", fn, &fs ); 01997 01998 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 01999 goto done; 02000 } 02001 02002 /**** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ****/ 02003 02004 #if defined ( PLPLOT_LIB_ENV ) 02005 if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL ) 02006 { 02007 plGetName( dn, "", fn, &fs ); 02008 02009 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 02010 goto done; 02011 fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); /* what IS set? */ 02012 } 02013 #endif /* PLPLOT_LIB_ENV */ 02014 02015 /**** search current directory ****/ 02016 02017 if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL ) 02018 { 02019 pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn ); 02020 free_mem( fs ); 02021 return ( file ); 02022 } 02023 02024 /**** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ****/ 02025 02026 #if defined ( PLPLOT_HOME_ENV ) 02027 if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL ) 02028 { 02029 plGetName( dn, "lib", fn, &fs ); 02030 02031 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 02032 goto done; 02033 fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); /* what IS set? */ 02034 } 02035 #endif /* PLPLOT_HOME_ENV/lib */ 02036 02037 /**** search installed location ****/ 02038 02039 #if defined ( DATA_DIR ) 02040 plGetName( DATA_DIR, "", fn, &fs ); 02041 02042 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 02043 goto done; 02044 #endif /* DATA_DIR */ 02045 02046 /**** search hardwired location ****/ 02047 02048 #ifdef PLLIBDEV 02049 plGetName( PLLIBDEV, "", fn, &fs ); 02050 02051 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 02052 goto done; 02053 #endif /* PLLIBDEV */ 02054 02055 #ifdef macintosh 02056 file = plMacLibOpen( fn ); 02057 if ( file != NULL ) 02058 goto done; 02059 #endif /* macintosh */ 02060 02061 if ( plplotLibDir != NULL ) 02062 { 02063 plGetName( plplotLibDir, "", fn, &fs ); 02064 if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL ) 02065 goto done; 02066 } 02067 02068 /**** not found, give up ****/ 02069 pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn ); 02070 free_mem( fs ); 02071 return NULL; 02072 02073 done: 02074 pldebug( "plLibOpenPdfstr", "Found file %s\n", fs ); 02075 free_mem( fs ); 02076 return ( file ); 02077 } 02078 02079 /*--------------------------------------------------------------------------*\ 02080 * int plFindName 02081 * 02082 * Authors: Paul Dubois (LLNL), others? 02083 * This function is in the public domain. 02084 * 02085 * Given a pathname, determine if it is a symbolic link. If so, continue 02086 * searching to the ultimate terminus - there may be more than one link. 02087 * Use the error value to determine when the terminus is reached, and to 02088 * determine if the pathname really exists. Then stat it to determine 02089 * whether it's executable. Return 0 for an executable, errno otherwise. 02090 * Note that 'p' _must_ have at least one '/' character - it does by 02091 * construction in this program. The contents of the array pointed to by 02092 * 'p' are changed to the actual pathname if findname is successful. 02093 * 02094 * This function is only defined under Unix for now. 02095 \*--------------------------------------------------------------------------*/ 02096 02097 #ifdef __unix 02098 int 02099 plFindName( char *p ) 02100 { 02101 int n; 02102 char buf[PLPLOT_MAX_PATH], *cp; 02103 extern int errno; 02104 struct stat sbuf; 02105 02106 pldebug( "plFindName", "Trying to find %s\n", p ); 02107 while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 ) 02108 { 02109 pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p ); 02110 if ( buf[0] == '/' ) 02111 { 02112 /* Link is an absolute path */ 02113 02114 strncpy( p, buf, n ); 02115 p[n] = '\0'; 02116 pldebug( "plFindName", "Link is absolute: %s\n", p ); 02117 } 02118 else 02119 { 02120 /* Link is relative to its directory; make it absolute */ 02121 02122 cp = 1 + strrchr( p, '/' ); 02123 strncpy( cp, buf, n ); 02124 cp[n] = '\0'; 02125 pldebug( "plFindName", 02126 "Link is relative: %s\n\tTotal path:%s\n", cp, p ); 02127 } 02128 } 02129 02130 /* This macro not defined on the NEC SX-3 */ 02131 02132 #ifdef SX 02133 #define S_ISREG( mode ) ( mode & S_IFREG ) 02134 #endif 02135 02136 /* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */ 02137 02138 if ( errno == EINVAL || errno == ENXIO ) 02139 { 02140 pldebug( "plFindName", "%s may be the one...\n", p ); 02141 if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) ) 02142 { 02143 pldebug( "plFindName", "%s is a regular file\n", p ); 02144 return ( access( p, X_OK ) ); 02145 } 02146 } 02147 pldebug( "plFindName", "%s found but is not executable\n", p ); 02148 return ( errno ? errno : -1 ); 02149 } 02150 02151 #else 02152 int 02153 plFindName( char *p ) 02154 { 02155 return 1; 02156 } 02157 #endif 02158 02159 /*--------------------------------------------------------------------------*\ 02160 * void plGetName() 02161 * 02162 * Gets search name for file by concatenating the dir, subdir, and file 02163 * name, allocating memory as needed. The appropriate delimiter is added 02164 * after the dir specification as necessary. The caller is responsible 02165 * for freeing the malloc'ed memory. 02166 \*--------------------------------------------------------------------------*/ 02167 02168 void 02169 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec ) 02170 { 02171 int lfilespec; 02172 02173 /* Malloc space for filespec */ 02174 02175 free_mem( *filespec ); 02176 lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10; 02177 if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL ) 02178 { 02179 plexit( "plGetName: Insufficient memory" ); 02180 } 02181 02182 strcpy( *filespec, dir ); 02183 02184 if ( *subdir != '\0' ) 02185 { 02186 strcat_delim( *filespec ); 02187 strcat( *filespec, subdir ); 02188 } 02189 if ( *filename != '\0' ) 02190 { 02191 strcat_delim( *filespec ); 02192 strcat( *filespec, filename ); 02193 } 02194 pldebug( "plGetName", "Length of full pathname of file to be found is %d\n", lfilespec ); 02195 pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec ); 02196 } 02197 02198 /*--------------------------------------------------------------------------*\ 02199 * void strcat_delim() 02200 * 02201 * Append path name deliminator if necessary (does not add one if one's 02202 * there already, or if dealing with a colon-terminated device name). 02203 \*--------------------------------------------------------------------------*/ 02204 02205 void 02206 strcat_delim( char *dirspec ) 02207 { 02208 int ldirspec = strlen( dirspec ); 02209 #if defined ( MSDOS ) || defined ( WIN32 ) 02210 if ( dirspec[ldirspec - 1] != '\\' ) 02211 strcat( dirspec, "\\" ); 02212 #elif defined ( macintosh ) 02213 if ( dirspec[ldirspec - 1] != ':' ) 02214 strcat( dirspec, ":" ); 02215 #else /* unix is the default */ 02216 if ( dirspec[ldirspec - 1] != '/' ) 02217 strcat( dirspec, "/" ); 02218 #endif 02219 } 02220 02221 /*--------------------------------------------------------------------------*\ 02222 * plcol_interp() 02223 * 02224 * Initializes device cmap 1 entry by interpolation from pls->cmap1 02225 * entries. Returned PLColor is supposed to represent the i_th color 02226 * out of a total of ncol colors in the current color scheme. 02227 \*--------------------------------------------------------------------------*/ 02228 02229 void 02230 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol ) 02231 { 02232 PLFLT x, delta; 02233 int il, ir; 02234 02235 x = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 ); 02236 il = (int) x; 02237 ir = il + 1; 02238 delta = x - il; 02239 02240 if ( ir > pls->ncol1 || il < 0 ) 02241 fprintf( stderr, "Invalid color\n" ); 02242 02243 else if ( ir == pls->ncol1 || ( delta == 0. ) ) 02244 { 02245 newcolor->r = pls->cmap1[il].r; 02246 newcolor->g = pls->cmap1[il].g; 02247 newcolor->b = pls->cmap1[il].b; 02248 newcolor->a = pls->cmap1[il].a; 02249 } 02250 else 02251 { 02252 newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r ); 02253 newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g ); 02254 newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b ); 02255 newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a; 02256 } 02257 } 02258 02259 /*--------------------------------------------------------------------------*\ 02260 * plOpenFile() 02261 * 02262 * Opens file for output, prompting if not set. 02263 * Prints extra newline at end to make output look better in batch runs. 02264 * A file name of "-" indicates output to stdout. 02265 \*--------------------------------------------------------------------------*/ 02266 02267 #define MAX_NUM_TRIES 10 02268 void 02269 plOpenFile( PLStream *pls ) 02270 { 02271 int i = 0, count = 0; 02272 size_t len; 02273 char line[BUFFER_SIZE]; 02274 02275 while ( pls->OutFile == NULL ) 02276 { 02277 /* Setting pls->FileName = NULL forces creation of a new family member */ 02278 /* You should also free the memory associated with it if you do this */ 02279 02280 if ( pls->family && pls->BaseName != NULL ) 02281 plP_getmember( pls ); 02282 02283 /* Prompt if filename still not known */ 02284 02285 if ( pls->FileName == NULL ) 02286 { 02287 do 02288 { 02289 fprintf( stdout, "Enter graphics output file name: " ); 02290 plio_fgets( line, sizeof ( line ), stdin ); 02291 len = strlen( line ); 02292 if ( len ) 02293 len--; 02294 line[len] = '\0'; /* strip new-line */ 02295 count++; /* count zero entries */ 02296 } while ( !len && count < MAX_NUM_TRIES ); 02297 plP_sfnam( pls, line ); 02298 } 02299 02300 /* If name is "-", send to stdout */ 02301 02302 if ( !strcmp( pls->FileName, "-" ) ) 02303 { 02304 pls->OutFile = stdout; 02305 pls->output_type = 1; 02306 break; 02307 } 02308 02309 /* Need this here again, for prompted family initialization */ 02310 02311 if ( pls->family && pls->BaseName != NULL ) 02312 plP_getmember( pls ); 02313 02314 if ( i++ > 10 ) 02315 plexit( "Too many tries." ); 02316 02317 if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL ) 02318 fprintf( stderr, "Can't open %s.\n", pls->FileName ); 02319 else 02320 pldebug( "plOpenFile", "Opened %s\n", pls->FileName ); 02321 } 02322 } 02323 02324 /*--------------------------------------------------------------------------*\ 02325 * plCloseFile() 02326 * 02327 * Closes output file unless it is associated with stdout. 02328 \*--------------------------------------------------------------------------*/ 02329 02330 void 02331 plCloseFile( PLStream *pls ) 02332 { 02333 if ( pls->OutFile != NULL ) 02334 { 02335 /* Don't close if the output file was stdout */ 02336 if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 ) 02337 return; 02338 02339 fclose( pls->OutFile ); 02340 pls->OutFile = NULL; 02341 } 02342 } 02343 02344 /*--------------------------------------------------------------------------*\ 02345 * plP_getmember() 02346 * 02347 * Sets up next file member name (in pls->FileName), but does not open it. 02348 \*--------------------------------------------------------------------------*/ 02349 02350 void 02351 plP_getmember( PLStream *pls ) 02352 { 02353 char tmp[BUFFER_SIZE]; 02354 char prefix[BUFFER_SIZE]; 02355 char * suffix; 02356 char num[BUFFER_SIZE]; 02357 int maxlen; 02358 02359 maxlen = strlen( pls->BaseName ) + 10; 02360 if ( pls->FileName == NULL ) 02361 { 02362 if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL ) 02363 { 02364 plexit( "plP_getmember: Insufficient memory" ); 02365 } 02366 } 02367 02368 suffix = strstr( pls->BaseName, "%n" ); 02369 02370 snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen ); 02371 snprintf( num, BUFFER_SIZE, tmp, pls->member ); 02372 02373 if ( suffix == NULL ) 02374 snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num ); 02375 else 02376 { 02377 strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 ); 02378 prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0'; 02379 snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 ); 02380 } 02381 } 02382 02383 /*--------------------------------------------------------------------------*\ 02384 * plP_sfnam() 02385 * 02386 * Sets up file name (with "%n" removed if present) & family stem name. 02387 * Reserve some extra space (10 chars) to hold an optional member number. 02388 \*--------------------------------------------------------------------------*/ 02389 02390 void 02391 plP_sfnam( PLStream *pls, const char *fnam ) 02392 { 02393 char prefix[BUFFER_SIZE]; 02394 char * suffix; 02395 int maxlen; 02396 pls->OutFile = NULL; 02397 02398 if ( pls->FileName != NULL ) 02399 free( (void *) pls->FileName ); 02400 02401 maxlen = 10 + strlen( fnam ); 02402 if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL ) 02403 { 02404 plexit( "plP_sfnam: Insufficient memory" ); 02405 } 02406 02407 suffix = strstr( fnam, "%n" ); 02408 02409 if ( suffix == NULL ) 02410 { 02411 strncpy( pls->FileName, fnam, maxlen - 1 ); 02412 pls->FileName[maxlen - 1] = '\0'; 02413 } 02414 else 02415 { 02416 strncpy( prefix, fnam, BUFFER_SIZE - 1 ); 02417 prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0'; 02418 snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 ); 02419 } 02420 02421 if ( pls->BaseName != NULL ) 02422 free( (void *) pls->BaseName ); 02423 02424 if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL ) 02425 { 02426 plexit( "plP_sfnam: Insufficient memory" ); 02427 } 02428 02429 strncpy( pls->BaseName, fnam, maxlen - 1 ); 02430 pls->BaseName[maxlen - 1] = '\0'; 02431 } 02432 02433 /*--------------------------------------------------------------------------*\ 02434 * plFamInit() 02435 * 02436 * Initializes family file parameters. 02437 \*--------------------------------------------------------------------------*/ 02438 02439 void 02440 plFamInit( PLStream *pls ) 02441 { 02442 if ( pls->family ) 02443 { 02444 pls->bytecnt = 0; 02445 if ( !pls->member ) 02446 pls->member = 1; 02447 if ( !pls->finc ) 02448 pls->finc = 1; 02449 if ( !pls->fflen ) 02450 pls->fflen = 1; 02451 if ( !pls->bytemax ) 02452 pls->bytemax = PL_FILESIZE_KB * 1000; 02453 } 02454 } 02455 02456 /*--------------------------------------------------------------------------*\ 02457 * plGetFam() 02458 * 02459 * Starts new member file of family file set if necessary. 02460 * 02461 * Note each member file is a complete graphics file (can be printed 02462 * individually), although 'plrender' will treat a family as a single 02463 * logical file if given the family name instead of the member name. 02464 \*--------------------------------------------------------------------------*/ 02465 02466 void 02467 plGetFam( PLStream *pls ) 02468 { 02469 PLFLT xpmm_loc, ypmm_loc; 02470 if ( pls->family ) 02471 { 02472 if ( pls->bytecnt > pls->bytemax || pls->famadv ) 02473 { 02474 PLINT local_page_status = pls->page_status; 02475 plP_tidy(); 02476 pls->member += pls->finc; 02477 pls->famadv = 0; 02478 plP_init(); 02479 /* Restore page status (normally AT_BOP) that was changed 02480 * to AT_EOP by plP_init. */ 02481 pls->page_status = local_page_status; 02482 02483 /* Apply compensating factor to original xpmm and ypmm so that 02484 * character aspect ratio is preserved when overall aspect ratio 02485 * is changed. */ 02486 plP_gpixmm( &xpmm_loc, &ypmm_loc ); 02487 plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor ); 02488 return; 02489 } 02490 } 02491 } 02492 02493 /*--------------------------------------------------------------------------*\ 02494 * plRotPhy() 02495 * 02496 * Rotates physical coordinates if necessary for given orientation. 02497 * Each time orient is incremented, the plot is rotated 90 deg clockwise. 02498 * Note: this is now used only to rotate by 90 degrees for devices that 02499 * expect portrait mode. 02500 \*--------------------------------------------------------------------------*/ 02501 02502 void 02503 plRotPhy( PLINT orient, PLINT xmin, PLINT ymin, PLINT xmax, PLINT ymax, 02504 PLINT *px, PLINT *py ) 02505 { 02506 int x, y; 02507 02508 x = *px; 02509 y = *py; 02510 02511 switch ( orient % 4 ) 02512 { 02513 case 1: 02514 *px = xmin + ( y - ymin ); 02515 *py = ymin + ( xmax - x ); 02516 break; 02517 02518 case 2: 02519 *px = xmin + ( xmax - x ); 02520 *py = ymin + ( ymax - y ); 02521 break; 02522 02523 case 3: 02524 *px = xmin + ( ymax - y ); 02525 *py = ymin + ( x - xmin ); 02526 break; 02527 02528 default: 02529 break; /* do nothing */ 02530 } 02531 } 02532 02533 /*--------------------------------------------------------------------------*\ 02534 * plAllocDev() 02535 * 02536 * Allocates a standard PLDev structure for device-specific data, stores 02537 * the address in pls->dev, and returns the address as well. 02538 \*--------------------------------------------------------------------------*/ 02539 02540 PLDev * 02541 plAllocDev( PLStream *pls ) 02542 { 02543 if ( pls->dev != NULL ) 02544 free( (void *) pls->dev ); 02545 02546 pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) ); 02547 if ( pls->dev == NULL ) 02548 plexit( "plAllocDev: cannot allocate memory\n" ); 02549 02550 return (PLDev *) pls->dev; 02551 } 02552 02553 /*--------------------------------------------------------------------------*\ 02554 * plGinInit() 02555 * 02556 * Just fills in the PLGraphicsIn with appropriate initial values. 02557 \*--------------------------------------------------------------------------*/ 02558 02559 void 02560 plGinInit( PLGraphicsIn *gin ) 02561 { 02562 gin->type = 0; 02563 gin->state = 0; 02564 gin->keysym = 0; 02565 gin->button = 0; 02566 gin->string[0] = '\0'; 02567 gin->pX = gin->pY = -1; 02568 gin->dX = gin->dY = 0.; 02569 gin->wX = gin->wY = 0.; 02570 } 02571 02572 /*--------------------------------------------------------------------------*\ 02573 * plGetInt() 02574 * 02575 * Prompts human to input an integer in response to given message. 02576 \*--------------------------------------------------------------------------*/ 02577 02578 PLINT 02579 plGetInt( const char *s ) 02580 { 02581 int m; 02582 int i = 0; 02583 char line[BUFFER_SIZE]; 02584 02585 while ( i++ < 10 ) 02586 { 02587 fputs( s, stdout ); 02588 plio_fgets( line, sizeof ( line ), stdin ); 02589 02590 #ifdef MSDOS 02591 m = atoi( line ); 02592 return ( m ); 02593 #else 02594 if ( sscanf( line, "%d", &m ) == 1 ) 02595 return ( m ); 02596 fprintf( stdout, "No value or value out of range; please try again\n" ); 02597 #endif 02598 } 02599 plexit( "Too many tries." ); 02600 return ( 0 ); 02601 } 02602 02603 /*--------------------------------------------------------------------------*\ 02604 * plGetFlt() 02605 * 02606 * Prompts human to input a float in response to given message. 02607 \*--------------------------------------------------------------------------*/ 02608 02609 PLFLT 02610 plGetFlt( const char *s ) 02611 { 02612 PLFLT m; 02613 double m1; 02614 int i = 0; 02615 char line[BUFFER_SIZE]; 02616 02617 while ( i++ < 10 ) 02618 { 02619 fputs( s, stdout ); 02620 plio_fgets( line, sizeof ( line ), stdin ); 02621 02622 #ifdef MSDOS 02623 m = atof( line ); 02624 return ( m ); 02625 #else 02626 if ( sscanf( line, "%lf", &m1 ) == 1 ) 02627 { 02628 m = (PLFLT) m1; 02629 return ( m ); 02630 } 02631 fprintf( stdout, "No value or value out of range; please try again\n" ); 02632 #endif 02633 } 02634 plexit( "Too many tries." ); 02635 return ( 0. ); 02636 } 02637 02638 /*--------------------------------------------------------------------------*\ 02639 * plstrdup() 02640 * 02641 * A replacement for strdup(), which isn't portable. 02642 * Caller responsible for freeing the allocated memory. 02643 \*--------------------------------------------------------------------------*/ 02644 02645 char PLDLLIMPEXP * 02646 plstrdup( const char *src ) 02647 { 02648 char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) ); 02649 if ( dest != NULL ) 02650 strcpy( dest, src ); 02651 else 02652 plabort( "Out of memory" ); 02653 02654 return dest; 02655 } 02656 02657 #ifndef PL_HAVE_SNPRINTF 02658 /*--------------------------------------------------------------------------*\ 02659 * plsnprintf() 02660 * 02661 * Dummy function for snprintf(). This function just calls 02662 * the unsafe function ignoring the string size. This function will 02663 * rarely be needed if ever. 02664 \*--------------------------------------------------------------------------*/ 02665 02666 int 02667 plsnprintf( char *buffer, int n, const char *format, ... ) 02668 { 02669 int ret; 02670 02671 va_list args; 02672 va_start( args, format ); 02673 ret = vsprintf( buffer, fmt, args ); 02674 va_end( argptr ); 02675 02676 /* Check if overrun occured */ 02677 if ( ret > n - 1 ) 02678 plabort( "plsnprintf: buffer overrun" ); 02679 02680 return ret; 02681 } 02682 02683 /*--------------------------------------------------------------------------*\ 02684 * plsnscanf() 02685 * 02686 * Dummy function for snscanf(). This function just calls 02687 * the unsafe function ignoring the string size. This function will 02688 * rarely be needed if ever. 02689 \*--------------------------------------------------------------------------*/ 02690 02691 int 02692 plsnscanf( const char *buffer, int n, const char *format, ... ) 02693 { 02694 int ret; 02695 02696 va_list argptr; 02697 va_start( argptr, format ); 02698 ret = vsscanf( buffer, fmt, args ); 02699 va_end( argptr ); 02700 02701 return ret; 02702 } 02703 02704 #endif /* PL_HAVE_SNPRINTF */ 02705 02706 /*--------------------------------------------------------------------------*\ 02707 * plseed() 02708 * 02709 * Set the seed for the random number generator included. 02710 \*--------------------------------------------------------------------------*/ 02711 02712 void 02713 c_plseed( unsigned int s ) 02714 { 02715 init_genrand( s ); 02716 } 02717 02718 /*--------------------------------------------------------------------------*\ 02719 * plrandd() 02720 * 02721 * Returns a random number on [0,1]-interval. 02722 \*--------------------------------------------------------------------------*/ 02723 02724 PLFLT 02725 c_plrandd( void ) 02726 { 02727 return (PLFLT) ( genrand_real1() ); 02728 } 02729 02730 /*--------------------------------------------------------------------------*\ 02731 * plsave_set_locale() 02732 * 02733 * Save LC_NUMERIC locale in a string. The pointer to that string is 02734 * returned. Then set LC_NUMERIC to "C" locale. 02735 * n.b. plsave_set_locale and plrestore_locale should always be used as 02736 * a pair to surround PLplot code that absolutely requires the 02737 * LC_NUMERIC "C" locale to be in effect. It is one of plrestore_locale's 02738 * responsibilities to free the memory allocated here for the locale 02739 * string. 02740 \*--------------------------------------------------------------------------*/ 02741 02742 char * 02743 plsave_set_locale( void ) 02744 { 02745 char * setlocale_ptr; 02746 char * saved_lc_numeric_locale; 02747 02748 if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) ) 02749 { 02750 plexit( "plsave_set_locale: out of memory" ); 02751 } 02752 02753 /*save original LC_NUMERIC locale for restore below. */ 02754 if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) ) 02755 { 02756 plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" ); 02757 } 02758 strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 ); 02759 saved_lc_numeric_locale[99] = '\0'; 02760 02761 /* Do not use pldebug since get overflowed stack (infinite recursion) 02762 * if device is interactive (i.e., pls->termin is set). */ 02763 /* comment out fprintf (unless there is some emergency debugging to do) 02764 * because output is too voluminous. */ 02765 /* 02766 * fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale); 02767 */ 02768 02769 if ( !( setlocale( LC_NUMERIC, "C" ) ) ) 02770 { 02771 plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" ); 02772 } 02773 return saved_lc_numeric_locale; 02774 } 02775 02776 /*--------------------------------------------------------------------------*\ 02777 * plrestore_locale() 02778 * 02779 * Restore LC_NUMERIC locale string that was determined by 02780 * plsave_set_locale with the pointer to that string as the argument. 02781 * Also, free the memory for that string. 02782 \*--------------------------------------------------------------------------*/ 02783 02784 void 02785 plrestore_locale( char *saved_lc_numeric_locale ) 02786 { 02787 /* Do not use pldebug since get overflowed stack (infinite recursion) 02788 * if device is interactive (i.e., pls->termin is set). */ 02789 /* comment out fprintf (unless there is some emergency debugging to do) 02790 * because output is too voluminous. */ 02791 /* 02792 * fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale); 02793 */ 02794 02795 if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) ) 02796 { 02797 char msgbuf[1024]; 02798 snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale ); 02799 plexit( msgbuf ); 02800 } 02801 free( saved_lc_numeric_locale ); 02802 } 02803