Back to index

plt-scheme  4.2.1
plcore.c
Go to the documentation of this file.
00001 /* $Id: plcore.c,v 1.2 2005/03/17 21:39:21 eli Exp $
00002 
00003        Central dispatch facility for PLplot.
00004        Also contains the PLplot main data structures, external access
00005        routines, and initialization calls.
00006 
00007        This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
00008 */
00009 
00010 #define DEBUG
00011 
00012 #define NEED_PLDEBUG
00013 #include "plcore.h"
00014 
00015 #ifdef ENABLE_DYNDRIVERS
00016 #include <ltdl.h>
00017 #endif
00018 
00019 /*--------------------------------------------------------------------------*\
00020  * Driver Interface
00021  *
00022  * These routines are the low-level interface to the driver -- all calls to
00023  * driver functions must pass through here.  For implementing driver-
00024  * specific functions, the escape function is provided.  The command stream
00025  * gets duplicated to the plot buffer here.
00026  *
00027  * All functions that result in graphics actually being plotted (rather than
00028  * just a change of state) are filtered as necessary before being passed on.
00029  * The default settings do not require any filtering, i.e.  PLplot physical
00030  * coordinates are the same as the device physical coordinates (currently
00031  * this can't be changed anyway), and a global view equal to the entire page
00032  * is used.
00033  *
00034  * The reason one wants to put view-specific filtering here is that if
00035  * enabled, the plot buffer should receive the unfiltered data stream.  This
00036  * allows a specific view to be used from an interactive device (e.g. TCL/TK
00037  * driver) but be restored to the full view at any time merely by
00038  * reprocessing the contents of the plot buffer.
00039  *
00040  * The metafile, on the other hand, *should* be affected by changes in the
00041  * view, since this is a crucial editing capability.  It is recommended that
00042  * the initial metafile be created without a restricted global view, and
00043  * modification of the view done on a per-plot basis as desired during
00044  * subsequent processing.
00045  *
00046 \*--------------------------------------------------------------------------*/
00047 
00048 enum {AT_BOP, DRAWING, AT_EOP};
00049 
00050 /* Initialize device. */
00051 /* The plot buffer must be called last */
00052 
00053 void
00054 plP_init(void)
00055 {
00056     plsc->page_status = AT_EOP;
00057 
00058     (*plsc->dispatch_table->pl_init) ((struct PLStream_struct *) plsc);
00059 
00060     if (plsc->plbuf_write)
00061        plbuf_init(plsc);
00062 }
00063 
00064 /* End of page */
00065 /* The plot buffer must be called first */
00066 /* Ignore instruction if there's nothing drawn */
00067 
00068 void
00069 plP_eop(void)
00070 {
00071     int skip_driver_eop = 0;
00072 
00073     if (plsc->page_status != DRAWING)
00074        return;
00075 
00076     plsc->page_status = AT_EOP;
00077 
00078     if (plsc->plbuf_write)
00079        plbuf_eop(plsc);
00080 
00081 /* Call user eop handler if present. */
00082 
00083     if (plsc->eop_handler != NULL)
00084        (*plsc->eop_handler) (plsc->eop_data, &skip_driver_eop);
00085 
00086     if (!skip_driver_eop)
00087        (*plsc->dispatch_table->pl_eop) ((struct PLStream_struct *) plsc);
00088 }
00089 
00090 /* Set up new page. */
00091 /* The plot buffer must be called last */
00092 /* Ignore if the bop was already issued. */
00093 /* It's not actually necessary to be AT_EOP here, so don't check for it. */
00094 
00095 void
00096 plP_bop(void)
00097 {
00098     int skip_driver_bop = 0;
00099 
00100     plP_subpInit();
00101     if (plsc->page_status == AT_BOP)
00102        return;
00103 
00104     plsc->page_status = AT_BOP;
00105     plsc->nplwin = 0;
00106 
00107 /* Call user bop handler if present. */
00108 
00109     if (plsc->bop_handler != NULL)
00110        (*plsc->bop_handler) (plsc->bop_data, &skip_driver_bop);
00111 
00112     if (!skip_driver_bop)
00113        (*plsc->dispatch_table->pl_bop) ((struct PLStream_struct *) plsc);
00114 
00115     if (plsc->plbuf_write)
00116        plbuf_bop(plsc);
00117 }
00118 
00119 /* Tidy up device (flush buffers, close file, etc). */
00120 
00121 void
00122 plP_tidy(void)
00123 {
00124     if (plsc->tidy) {
00125        (*plsc->tidy) (plsc->tidy_data);
00126        plsc->tidy = NULL;
00127        plsc->tidy_data = NULL;
00128     }
00129 
00130     (*plsc->dispatch_table->pl_tidy) ((struct PLStream_struct *) plsc);
00131 
00132     if (plsc->plbuf_write)
00133        plbuf_tidy(plsc);
00134 
00135     plsc->OutFile = NULL;
00136     free_mem(plsc->FileName);
00137 }
00138 
00139 /* Change state. */
00140 
00141 void
00142 plP_state(PLINT op)
00143 {
00144     (*plsc->dispatch_table->pl_state) ((struct PLStream_struct *) plsc, op);
00145 
00146     if (plsc->plbuf_write)
00147        plbuf_state(plsc, op);
00148 }
00149 
00150 /* Escape function, for driver-specific commands. */
00151 
00152 void
00153 plP_esc(PLINT op, void *ptr)
00154 {
00155     (*plsc->dispatch_table->pl_esc) ((struct PLStream_struct *) plsc, op, ptr);
00156 
00157     if (plsc->plbuf_write)
00158        plbuf_esc(plsc, op, ptr);
00159 }
00160 
00161 /* Set up plot window parameters. */
00162 /* The plot buffer must be called first */
00163 /* Some drivers (metafile, Tk) need access to this data */
00164 
00165 void
00166 plP_swin(PLWindow *plwin)
00167 {
00168     PLWindow *w;
00169     PLINT clpxmi, clpxma, clpymi, clpyma;
00170 
00171 /* Provide plot buffer with unfiltered window data */
00172 
00173     if (plsc->plbuf_write)
00174        plbuf_esc(plsc, PLESC_SWIN, (void *) plwin);
00175 
00176     w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
00177 
00178     w->dxmi = plwin->dxmi;
00179     w->dxma = plwin->dxma;
00180     w->dymi = plwin->dymi;
00181     w->dyma = plwin->dyma;
00182 
00183     if (plsc->difilt) {
00184        xscl[0] = plP_dcpcx(w->dxmi);
00185        xscl[1] = plP_dcpcx(w->dxma);
00186        yscl[0] = plP_dcpcy(w->dymi);
00187        yscl[1] = plP_dcpcy(w->dyma);
00188 
00189        difilt(xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma);
00190 
00191        w->dxmi = plP_pcdcx(xscl[0]);
00192        w->dxma = plP_pcdcx(xscl[1]);
00193        w->dymi = plP_pcdcy(yscl[0]);
00194        w->dyma = plP_pcdcy(yscl[1]);
00195     }
00196 
00197     w->wxmi = plwin->wxmi;
00198     w->wxma = plwin->wxma;
00199     w->wymi = plwin->wymi;
00200     w->wyma = plwin->wyma;
00201 
00202 /* If the driver wants to process swin commands, call it now */
00203 /* It must use the filtered data, which it can get from *plsc */
00204 
00205     if (plsc->dev_swin) {
00206        (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
00207                                           PLESC_SWIN, NULL );
00208     }
00209 }
00210 
00211 /*--------------------------------------------------------------------------*\
00212  *  Drawing commands.
00213 \*--------------------------------------------------------------------------*/
00214 
00215 /* Draw line between two points */
00216 /* The plot buffer must be called first so it gets the unfiltered data */
00217 
00218 void
00219 plP_line(short *x, short *y)
00220 {
00221     PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
00222 
00223     plsc->page_status = DRAWING;
00224 
00225     if (plsc->plbuf_write)
00226        plbuf_line(plsc, x[0], y[0], x[1], y[1]);
00227 
00228     if (plsc->difilt) {
00229        for (i = 0; i < npts; i++) {
00230            xscl[i] = x[i];
00231            yscl[i] = y[i];
00232        }
00233        difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
00234        plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
00235     }
00236     else {
00237        grline(x, y, npts);
00238     }
00239 }
00240 
00241 /* Draw polyline */
00242 /* The plot buffer must be called first */
00243 
00244 void
00245 plP_polyline(short *x, short *y, PLINT npts)
00246 {
00247     PLINT i, clpxmi, clpxma, clpymi, clpyma;
00248 
00249     plsc->page_status = DRAWING;
00250 
00251     if (plsc->plbuf_write)
00252        plbuf_polyline(plsc, x, y, npts);
00253 
00254     if (plsc->difilt) {
00255        for (i = 0; i < npts; i++) {
00256            xscl[i] = x[i];
00257            yscl[i] = y[i];
00258        }
00259        difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
00260        plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
00261                  grpolyline);
00262     }
00263     else {
00264        grpolyline(x, y, npts);
00265     }
00266 }
00267 
00268 /* Fill polygon */
00269 /* The plot buffer must be called first */
00270 /* Here if the desired area fill capability isn't present, we mock up */
00271 /* something in software */
00272 
00273 static int foo;
00274 
00275 void
00276 plP_fill(short *x, short *y, PLINT npts)
00277 {
00278     PLINT i, clpxmi, clpxma, clpymi, clpyma;
00279 
00280     plsc->page_status = DRAWING;
00281 
00282     if (plsc->plbuf_write) {
00283        plsc->dev_npts = npts;
00284        plsc->dev_x = x;
00285        plsc->dev_y = y;
00286        plbuf_esc(plsc, PLESC_FILL, NULL);
00287     }
00288 
00289 /* Account for driver ability to do fills */
00290 
00291     if (plsc->patt == 0 && ! plsc->dev_fill0) {
00292        if ( ! foo) {
00293            plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
00294            foo = 1;
00295        }
00296        plsc->patt = 8;
00297        plpsty(plsc->patt);
00298     }
00299     if (plsc->dev_fill1) {
00300        plsc->patt = -ABS(plsc->patt);
00301     }
00302 
00303 /* Perform fill.  Here we MUST NOT allow the software fill to pass through the
00304    driver interface filtering twice, else we get the infamous 2*rotation for
00305    software fills on orientation swaps. 
00306 */
00307 
00308     if (plsc->patt > 0)
00309        plfill_soft(x, y, npts);
00310 
00311     else {
00312        if (plsc->difilt) {
00313            for (i = 0; i < npts; i++) {
00314               xscl[i] = x[i];
00315               yscl[i] = y[i];
00316            }
00317            difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
00318            plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
00319                      grfill);
00320        }
00321        else {
00322            grfill(x, y, npts);
00323        }
00324     }
00325 }
00326 
00327 /* Account for driver ability to draw text itself */
00328 /*
00329 #define DEBUG_TEXT
00330 */
00331 
00332 void
00333 plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
00334         PLINT refx, PLINT refy, const char *string)
00335 {
00336     if (plsc->dev_text) {
00337        EscText args;
00338 
00339        args.base = base;
00340        args.just = just;
00341        args.xform = xform;
00342        args.x = x;
00343        args.y = y;
00344        args.refx = refx;
00345        args.refy = refy;
00346        args.string = string;
00347 
00348        if (plsc->plbuf_write)
00349            plbuf_esc(plsc, PLESC_HAS_TEXT, &args);
00350 
00351        plP_esc(PLESC_HAS_TEXT, &args);
00352 #ifndef DEBUG_TEXT
00353     } else {
00354 #endif
00355        plstr(base, xform, refx, refy, string);
00356     }
00357 }
00358 
00359 static void
00360 grline(short *x, short *y, PLINT npts)
00361 {
00362     (*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
00363                                        x[0], y[0], x[1], y[1] );
00364 }
00365 
00366 static void
00367 grpolyline(short *x, short *y, PLINT npts)
00368 {
00369     (*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
00370                                            x, y, npts );
00371 }
00372 
00373 static void
00374 grfill(short *x, short *y, PLINT npts)
00375 {
00376     plsc->dev_npts = npts;
00377     plsc->dev_x = x;
00378     plsc->dev_y = y;
00379 
00380     (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
00381                                       PLESC_FILL, NULL );
00382 }
00383 
00384 /*--------------------------------------------------------------------------*\
00385  * void difilt
00386  *
00387  * Driver interface filter -- passes all coordinates through a variety
00388  * of filters.  These include filters to change :
00389  *
00390  *     - mapping of meta to physical coordinates
00391  *     - plot orientation
00392  *     - window into plot (zooms)
00393  *     - window into device (i.e set margins)
00394  *
00395  * The filters are applied in the order specified above.  Because the
00396  * orientation change comes first, subsequent window specifications affect
00397  * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
00398  * This is the only way that makes sense from a graphical interface
00399  * (e.g. TCL/TK driver).
00400  *
00401  * Where appropriate, the page clip limits are modified.
00402 \*--------------------------------------------------------------------------*/
00403 
00404 void
00405 difilt(PLINT *xscl, PLINT *yscl, PLINT npts,
00406        PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
00407 {
00408     PLINT i, x, y;
00409 
00410 /* Map meta coordinates to physical coordinates */
00411 
00412     if (plsc->difilt & PLDI_MAP) {
00413        for (i = 0; i < npts; i++) {
00414            xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
00415            yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
00416        }
00417     }
00418 
00419 /* Change orientation */
00420 
00421     if (plsc->difilt & PLDI_ORI) {
00422        for (i = 0; i < npts; i++) {
00423            x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
00424            y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
00425            xscl[i] = x;
00426            yscl[i] = y;
00427        }
00428     }
00429 
00430 /* Change window into plot space */
00431 
00432     if (plsc->difilt & PLDI_PLT) {
00433        for (i = 0; i < npts; i++) {
00434            xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
00435            yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
00436        }
00437     }
00438 
00439 /* Change window into device space and set clip limits */
00440 /* (this is the only filter that modifies them) */
00441 
00442     if (plsc->difilt & PLDI_DEV) {
00443        for (i = 0; i < npts; i++) {
00444            xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
00445            yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
00446        }
00447        *clpxmi = plsc->diclpxmi;
00448        *clpxma = plsc->diclpxma;
00449        *clpymi = plsc->diclpymi;
00450        *clpyma = plsc->diclpyma;
00451     }
00452     else {
00453       *clpxmi = plsc->phyxmi;
00454       *clpxma = plsc->phyxma;
00455       *clpymi = plsc->phyymi;
00456       *clpyma = plsc->phyyma;
00457     }
00458 }
00459 
00460 void
00461 sdifilt(short *xscl, short *yscl, PLINT npts,
00462        PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
00463 {
00464   int i;
00465   short x, y;
00466 
00467 /* Map meta coordinates to physical coordinates */
00468 
00469     if (plsc->difilt & PLDI_MAP) {
00470     for (i = 0; i < npts; i++) {
00471         xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
00472         yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
00473     }
00474     }
00475 
00476 /* Change orientation */
00477 
00478     if (plsc->difilt & PLDI_ORI) {
00479     for (i = 0; i < npts; i++) {
00480         x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
00481         y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
00482         xscl[i] = x;
00483         yscl[i] = y;
00484     }
00485     }
00486 
00487 /* Change window into plot space */
00488 
00489     if (plsc->difilt & PLDI_PLT) {
00490     for (i = 0; i < npts; i++) {
00491         xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
00492         yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
00493     }
00494     }
00495 
00496 /* Change window into device space and set clip limits */
00497 /* (this is the only filter that modifies them) */
00498 
00499     if (plsc->difilt & PLDI_DEV) {
00500     for (i = 0; i < npts; i++) {
00501         xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
00502         yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
00503     }
00504     *clpxmi = plsc->diclpxmi;
00505     *clpxma = plsc->diclpxma;
00506     *clpymi = plsc->diclpymi;
00507     *clpyma = plsc->diclpyma;
00508     }
00509     else {
00510     *clpxmi = plsc->phyxmi;
00511     *clpxma = plsc->phyxma;
00512     *clpymi = plsc->phyymi;
00513     *clpyma = plsc->phyyma;
00514     }
00515 }
00516 
00517 /*--------------------------------------------------------------------------*\
00518  * void pldi_ini
00519  *
00520  * Updates driver interface, making sure everything is in order.
00521  * Even if filter is not being used, the defaults need to be set up.
00522 \*--------------------------------------------------------------------------*/
00523 
00524 static void
00525 setdef_diplt()
00526 {
00527     plsc->dipxmin = 0.0;
00528     plsc->dipxmax = 1.0;
00529     plsc->dipymin = 0.0;
00530     plsc->dipymax = 1.0;
00531 }
00532 
00533 static void
00534 setdef_didev()
00535 {
00536     plsc->mar = 0.0;
00537     plsc->aspect = 0.0;
00538     plsc->jx = 0.0;
00539     plsc->jy = 0.0;
00540 }
00541 
00542 static void
00543 setdef_diori()
00544 {
00545     plsc->diorot = 0.;
00546 }
00547 
00548 static void
00549 pldi_ini(void)
00550 {
00551     if (plsc->level >= 1) {
00552        if (plsc->difilt & PLDI_MAP)       /* Coordinate mapping */
00553            calc_dimap();
00554 
00555        if (plsc->difilt & PLDI_ORI)       /* Orientation */
00556            calc_diori();
00557        else
00558            setdef_diori();
00559 
00560        if (plsc->difilt & PLDI_PLT)       /* Plot window */
00561            calc_diplt();
00562        else
00563            setdef_diplt();
00564 
00565        if (plsc->difilt & PLDI_DEV)       /* Device window */
00566            calc_didev();
00567        else
00568            setdef_didev();
00569     }
00570 }
00571 
00572 /*--------------------------------------------------------------------------*\
00573  * void pldid2pc
00574  *
00575  * Converts input values from relative device coordinates to relative plot
00576  * coordinates.  This function must be called when selecting a plot window
00577  * from a display driver, since the coordinates chosen by the user are
00578  * necessarily device-specific.
00579 \*--------------------------------------------------------------------------*/
00580 
00581 void
00582 pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
00583 {
00584     PLFLT pxmin, pymin, pxmax, pymax;
00585     PLFLT sxmin, symin, sxmax, symax;
00586     PLFLT rxmin, rymin, rxmax, rymax;
00587 
00588     if (plsc->difilt & PLDI_DEV) {
00589 
00590        pldebug("pldid2pc",
00591               "Relative device coordinates (in): %f, %f, %f, %f\n",
00592               *xmin, *ymin, *xmax, *ymax);
00593 
00594        pxmin = plP_dcpcx(*xmin);
00595        pymin = plP_dcpcy(*ymin);
00596        pxmax = plP_dcpcx(*xmax);
00597        pymax = plP_dcpcy(*ymax);
00598 
00599        sxmin = (pxmin - plsc->didxb) / plsc->didxax;
00600        symin = (pymin - plsc->didyb) / plsc->didyay;
00601        sxmax = (pxmax - plsc->didxb) / plsc->didxax;
00602        symax = (pymax - plsc->didyb) / plsc->didyay;
00603 
00604        rxmin = plP_pcdcx(sxmin);
00605        rymin = plP_pcdcy(symin);
00606        rxmax = plP_pcdcx(sxmax);
00607        rymax = plP_pcdcy(symax);
00608 
00609        *xmin = (rxmin < 0) ? 0 : rxmin;
00610        *xmax = (rxmax > 1) ? 1 : rxmax;
00611        *ymin = (rymin < 0) ? 0 : rymin;
00612        *ymax = (rymax > 1) ? 1 : rymax;
00613 
00614        pldebug("pldid2pc",
00615               "Relative plot coordinates (out): %f, %f, %f, %f\n",
00616               rxmin, rymin, rxmax, rymax);
00617     }
00618 }
00619 
00620 /*--------------------------------------------------------------------------*\
00621  * void pldip2dc
00622  *
00623  * Converts input values from relative plot coordinates to relative
00624  * device coordinates.
00625 \*--------------------------------------------------------------------------*/
00626 
00627 void
00628 pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
00629 {
00630     PLFLT pxmin, pymin, pxmax, pymax;
00631     PLFLT sxmin, symin, sxmax, symax;
00632     PLFLT rxmin, rymin, rxmax, rymax;
00633 
00634     if (plsc->difilt & PLDI_DEV) {
00635 
00636        pldebug("pldip2pc",
00637               "Relative plot coordinates (in): %f, %f, %f, %f\n",
00638               *xmin, *ymin, *xmax, *ymax);
00639 
00640        pxmin = plP_dcpcx(*xmin);
00641        pymin = plP_dcpcy(*ymin);
00642        pxmax = plP_dcpcx(*xmax);
00643        pymax = plP_dcpcy(*ymax);
00644 
00645        sxmin = pxmin * plsc->didxax + plsc->didxb;
00646        symin = pymin * plsc->didyay + plsc->didyb;
00647        sxmax = pxmax * plsc->didxax + plsc->didxb;
00648        symax = pymax * plsc->didyay + plsc->didyb;
00649 
00650        rxmin = plP_pcdcx(sxmin);
00651        rymin = plP_pcdcy(symin);
00652        rxmax = plP_pcdcx(sxmax);
00653        rymax = plP_pcdcy(symax);
00654 
00655        *xmin = (rxmin < 0) ? 0 : rxmin;
00656        *xmax = (rxmax > 1) ? 1 : rxmax;
00657        *ymin = (rymin < 0) ? 0 : rymin;
00658        *ymax = (rymax > 1) ? 1 : rymax;
00659 
00660        pldebug("pldip2pc",
00661               "Relative device coordinates (out): %f, %f, %f, %f\n",
00662               rxmin, rymin, rxmax, rymax);
00663     }
00664 }
00665 
00666 /*--------------------------------------------------------------------------*\
00667  * void plsdiplt
00668  *
00669  * Set window into plot space
00670 \*--------------------------------------------------------------------------*/
00671 
00672 void
00673 c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
00674 {
00675     plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
00676     plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
00677     plsc->dipymin = (ymin < ymax) ? ymin : ymax;
00678     plsc->dipymax = (ymin < ymax) ? ymax : ymin;
00679 
00680     if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.)  {
00681        plsc->difilt &= ~PLDI_PLT;
00682        return;
00683     }
00684 
00685     plsc->difilt |= PLDI_PLT;
00686     pldi_ini();
00687 }
00688 
00689 /*--------------------------------------------------------------------------*\
00690  * void plsdiplz
00691  *
00692  * Set window into plot space incrementally (zoom)
00693 \*--------------------------------------------------------------------------*/
00694 
00695 void
00696 c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
00697 {
00698     if (plsc->difilt & PLDI_PLT) {
00699        xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
00700        ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
00701        xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
00702        ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
00703     }
00704 
00705     plsdiplt(xmin, ymin, xmax, ymax);
00706 }
00707 
00708 /*--------------------------------------------------------------------------*\
00709  * void calc_diplt
00710  *
00711  * Calculate transformation coefficients to set window into plot space.
00712  *
00713  * Note: if driver has requested to handle these commands itself, we must
00714  * send the appropriate escape command.  If the driver succeeds it will
00715  * cancel the filter operation.  The command is deferred until this point
00716  * to ensure that the driver has been initialized.
00717 \*--------------------------------------------------------------------------*/
00718 
00719 static void
00720 calc_diplt(void)
00721 {
00722     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
00723 
00724     if (plsc->dev_di) {
00725        (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
00726                                           PLESC_DI, NULL );
00727     }
00728 
00729     if ( ! (plsc->difilt & PLDI_PLT))
00730        return;
00731 
00732     pxmin = plP_dcpcx(plsc->dipxmin);
00733     pxmax = plP_dcpcx(plsc->dipxmax);
00734     pymin = plP_dcpcy(plsc->dipymin);
00735     pymax = plP_dcpcy(plsc->dipymax);
00736 
00737     pxlen = pxmax - pxmin;
00738     pylen = pymax - pymin;
00739     pxlen = MAX(1, pxlen);
00740     pylen = MAX(1, pylen);
00741 
00742     plsc->dipxax = plsc->phyxlen / (double) pxlen;
00743     plsc->dipyay = plsc->phyylen / (double) pylen;
00744     plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
00745     plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
00746 }
00747 
00748 /*--------------------------------------------------------------------------*\
00749  * void plgdiplt
00750  *
00751  * Retrieve current window into plot space
00752 \*--------------------------------------------------------------------------*/
00753 
00754 void
00755 c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
00756 {
00757     *p_xmin = plsc->dipxmin;
00758     *p_xmax = plsc->dipxmax;
00759     *p_ymin = plsc->dipymin;
00760     *p_ymax = plsc->dipymax;
00761 }
00762 
00763 /*--------------------------------------------------------------------------*\
00764  * void plsdidev
00765  *
00766  * Set window into device space using margin, aspect ratio, and
00767  * justification.  If you want to just use the previous value for any of
00768  * these, just pass in the magic value PL_NOTSET.
00769  *
00770  * It is unlikely that one should ever need to change the aspect ratio
00771  * but it's in there for completeness.
00772 \*--------------------------------------------------------------------------*/
00773 
00774 void
00775 c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
00776 {
00777     plsetvar(plsc->mar, mar);
00778     plsetvar(plsc->aspect, aspect);
00779     plsetvar(plsc->jx, jx);
00780     plsetvar(plsc->jy, jy);
00781 
00782     if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. && 
00783        ! (plsc->difilt & PLDI_ORI)) {
00784        plsc->difilt &= ~PLDI_DEV;
00785        return;
00786     }
00787 
00788     plsc->difilt |= PLDI_DEV;
00789     pldi_ini();
00790 }
00791 
00792 /*--------------------------------------------------------------------------*\
00793  * void calc_didev
00794  *
00795  * Calculate transformation coefficients to set window into device space.
00796  * Calculates relative window bounds and calls plsdidxy to finish the job.
00797 \*--------------------------------------------------------------------------*/
00798 
00799 static void
00800 calc_didev(void)
00801 {
00802     PLFLT lx, ly, aspect, aspdev;
00803     PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
00804     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
00805 
00806     if (plsc->dev_di) {
00807        (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
00808                                           PLESC_DI, NULL );
00809     }
00810 
00811     if ( ! (plsc->difilt & PLDI_DEV))
00812        return;
00813 
00814 /* Calculate aspect ratio of physical device */
00815 
00816     lx = plsc->phyxlen / plsc->xpmm;
00817     ly = plsc->phyylen / plsc->ypmm;
00818     aspdev = lx / ly;
00819 
00820     if (plsc->difilt & PLDI_ORI)
00821        aspect = plsc->aspori;
00822     else
00823        aspect = plsc->aspect;
00824 
00825     if (aspect <= 0.)
00826        aspect = plsc->aspdev;
00827 
00828 /* Failsafe */
00829 
00830     plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
00831     plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
00832     plsc->jx = (plsc->jx >  0.5) ?  0.5 : plsc->jx;
00833     plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
00834     plsc->jy = (plsc->jy >  0.5) ?  0.5 : plsc->jy;
00835     plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
00836 
00837 /* Relative device coordinates that neutralize aspect ratio difference */
00838 
00839     xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
00840     ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
00841 
00842     xlen *= (1.0 - 2.*plsc->mar);
00843     ylen *= (1.0 - 2.*plsc->mar);
00844 
00845     xmin = (1. - xlen) * (0.5 + plsc->jx);
00846     xmax = xmin + xlen;
00847 
00848     ymin = (1. - ylen) * (0.5 + plsc->jy);
00849     ymax = ymin + ylen;
00850 
00851 /* Calculate transformation coefficients */
00852 
00853     pxmin = plP_dcpcx(xmin);
00854     pxmax = plP_dcpcx(xmax);
00855     pymin = plP_dcpcy(ymin);
00856     pymax = plP_dcpcy(ymax);
00857 
00858     pxlen = pxmax - pxmin;
00859     pylen = pymax - pymin;
00860     pxlen = MAX(1, pxlen);
00861     pylen = MAX(1, pylen);
00862 
00863     plsc->didxax = pxlen / (double) plsc->phyxlen;
00864     plsc->didyay = pylen / (double) plsc->phyylen;
00865     plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
00866     plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
00867 
00868 /* Set clip limits to conform to new page size */
00869 
00870     plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
00871     plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
00872     plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
00873     plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
00874 }
00875 
00876 /*--------------------------------------------------------------------------*\
00877  * void plgdidev
00878  *
00879  * Retrieve current window into device space
00880 \*--------------------------------------------------------------------------*/
00881 
00882 void
00883 c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
00884 {
00885     *p_mar = plsc->mar;
00886     *p_aspect = plsc->aspect;
00887     *p_jx = plsc->jx;
00888     *p_jy = plsc->jy;
00889 }
00890 
00891 /*--------------------------------------------------------------------------*\
00892  * void plsdiori
00893  *
00894  * Set plot orientation, specifying rotation in units of pi/2.
00895 \*--------------------------------------------------------------------------*/
00896 
00897 void
00898 c_plsdiori(PLFLT rot)
00899 {
00900     plsc->diorot = rot;
00901     if (rot == 0.) {
00902        plsc->difilt &= ~PLDI_ORI;
00903        pldi_ini();
00904        return;
00905     }
00906 
00907     plsc->difilt |= PLDI_ORI;
00908     pldi_ini();
00909 }
00910 
00911 /*--------------------------------------------------------------------------*\
00912  * void calc_diori
00913  *
00914  * Calculate transformation coefficients to arbitrarily orient plot.
00915  * Preserve aspect ratios so the output doesn't suck.
00916 \*--------------------------------------------------------------------------*/
00917 
00918 static void
00919 calc_diori(void)
00920 {
00921     PLFLT r11, r21, r12, r22, cost, sint;
00922     PLFLT x0, y0, lx, ly, aspect;
00923 
00924     if (plsc->dev_di) {
00925        (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
00926                                           PLESC_DI, NULL );
00927     }
00928 
00929     if ( ! (plsc->difilt & PLDI_ORI))
00930        return;
00931 
00932 /* Center point of rotation */
00933 
00934     x0 = (plsc->phyxma + plsc->phyxmi) / 2.;
00935     y0 = (plsc->phyyma + plsc->phyymi) / 2.;
00936 
00937 /* Rotation matrix */
00938 
00939     r11 = cos(plsc->diorot * PI / 2.);
00940     r21 = sin(plsc->diorot * PI / 2.);
00941     r12 = -r21;
00942     r22 = r11;
00943 
00944     cost = ABS(r11);
00945     sint = ABS(r21);
00946 
00947 /* Flip aspect ratio as necessary.  Grungy but I don't see a better way */
00948 
00949     aspect = plsc->aspect;
00950     if (aspect == 0.)
00951        aspect = plsc->aspdev;
00952 
00953     if (plsc->freeaspect)
00954        plsc->aspori = aspect;
00955     else
00956        plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
00957 
00958     if ( ! (plsc->difilt & PLDI_DEV)) {
00959        plsc->difilt |= PLDI_DEV;
00960        setdef_didev();
00961     }
00962     calc_didev();
00963 
00964 /* Compute scale factors */
00965 
00966     lx = plsc->phyxlen;
00967     ly = plsc->phyylen;
00968 
00969 /* Transformation coefficients */
00970 
00971     plsc->dioxax = r11;
00972     plsc->dioxay = r21 * (lx / ly);
00973     plsc->dioxb = (1. - r11) * x0 - r21 * y0 * (lx / ly);
00974 
00975     plsc->dioyax = r12 * (ly / lx);
00976     plsc->dioyay = r22;
00977     plsc->dioyb = (1. - r22) * y0 - r12 * x0 * (ly / lx);
00978 }
00979 
00980 /*--------------------------------------------------------------------------*\
00981  * void plgdiori
00982  *
00983  * Get plot orientation
00984 \*--------------------------------------------------------------------------*/
00985 
00986 void
00987 c_plgdiori(PLFLT *p_rot)
00988 {
00989     *p_rot = plsc->diorot;
00990 }
00991 
00992 /*--------------------------------------------------------------------------*\
00993  * void plsdimap
00994  *
00995  * Set up transformation from metafile coordinates.  The size of the plot is
00996  * scaled so as to preserve aspect ratio.  This isn't intended to be a
00997  * general-purpose facility just yet (not sure why the user would need it,
00998  * for one).
00999 \*--------------------------------------------------------------------------*/
01000 
01001 void
01002 c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
01003           PLFLT dimxpmm, PLFLT dimypmm)
01004 {
01005     plsetvar(plsc->dimxmin, dimxmin);
01006     plsetvar(plsc->dimxmax, dimxmax);
01007     plsetvar(plsc->dimymin, dimymin);
01008     plsetvar(plsc->dimymax, dimymax);
01009     plsetvar(plsc->dimxpmm, dimxpmm);
01010     plsetvar(plsc->dimypmm, dimypmm);
01011 
01012     plsc->difilt |= PLDI_MAP;
01013     pldi_ini();
01014 }
01015 
01016 /*--------------------------------------------------------------------------*\
01017  * void calc_dimap
01018  *
01019  * Set up transformation from metafile coordinates.  The size of the plot is
01020  * scaled so as to preserve aspect ratio.  This isn't intended to be a
01021  * general-purpose facility just yet (not sure why the user would need it,
01022  * for one).
01023 \*--------------------------------------------------------------------------*/
01024 
01025 static void
01026 calc_dimap()
01027 {
01028     PLFLT lx, ly;
01029     PLINT pxmin, pxmax, pymin, pymax;
01030     PLFLT dimxlen, dimylen, pxlen, pylen;
01031 
01032     if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
01033        (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
01034        (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
01035        plsc->difilt &= ~PLDI_MAP;
01036        return;
01037     }
01038 
01039 /* Set default aspect ratio */
01040 
01041     lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
01042     ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
01043 
01044     plsc->aspdev = lx / ly;
01045 
01046 /* Build transformation to correct physical coordinates */
01047 
01048     dimxlen = plsc->dimxmax - plsc->dimxmin;
01049     dimylen = plsc->dimymax - plsc->dimymin;
01050 
01051     pxmin = plsc->phyxmi;
01052     pxmax = plsc->phyxma;
01053     pymin = plsc->phyymi;
01054     pymax = plsc->phyyma;
01055     pxlen = pxmax - pxmin;
01056     pylen = pymax - pymin;
01057 
01058     plsc->dimxax = pxlen / dimxlen;
01059     plsc->dimyay = pylen / dimylen;
01060     plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
01061     plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
01062 }
01063 
01064 /*--------------------------------------------------------------------------*\
01065  * void plflush()
01066  *
01067  * Flushes the output stream.  Use sparingly, if at all.
01068 \*--------------------------------------------------------------------------*/
01069 
01070 void
01071 c_plflush(void)
01072 {
01073     if (plsc->dev_flush) {
01074        (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
01075                                           PLESC_FLUSH, NULL );
01076     }
01077     else {
01078        if (plsc->OutFile != NULL)
01079            fflush(plsc->OutFile);
01080     }
01081 }
01082 
01083 /*--------------------------------------------------------------------------*\
01084  * Startup routines.
01085 \*--------------------------------------------------------------------------*/
01086 
01087 /*--------------------------------------------------------------------------*\
01088  * void pllib_init()
01089  *
01090  * Initialize library.  Called internally by every startup routine.
01091  * Everything you want to always be initialized before plinit() is called
01092  * you should put here.  E.g. dispatch table setup, rcfile read, etc.
01093 \*--------------------------------------------------------------------------*/
01094 
01095 void
01096 pllib_init()
01097 {
01098     if (lib_initialized) return;
01099     lib_initialized = 1;
01100 
01101 #ifdef ENABLE_DYNDRIVERS
01102 /* Create libltdl resources */
01103         lt_dlinit();   
01104 #endif
01105 
01106 /* Initialize the dispatch table with the info from the static drivers table
01107    and the available dynamic drivers. */
01108 
01109     plInitDispatchTable();
01110 }
01111 
01112 /*--------------------------------------------------------------------------*\
01113  * void plstar(nx, ny)
01114  *
01115  * Initialize PLplot, passing in the windows/page settings.
01116 \*--------------------------------------------------------------------------*/
01117 
01118 void
01119 c_plstar(PLINT nx, PLINT ny)
01120 {
01121     pllib_init();
01122 
01123     if (plsc->level != 0)
01124        plend1();
01125 
01126     plssub(nx, ny);
01127 
01128     c_plinit();
01129 }
01130 
01131 /*--------------------------------------------------------------------------*\
01132  * void plstart(devname, nx, ny)
01133  *
01134  * Initialize PLplot, passing the device name and windows/page settings. 
01135 \*--------------------------------------------------------------------------*/
01136 
01137 void
01138 c_plstart(const char *devname, PLINT nx, PLINT ny)
01139 {
01140     pllib_init();
01141 
01142     if (plsc->level != 0)
01143        plend1();
01144 
01145     plssub(nx, ny);
01146     plsdev(devname);
01147 
01148     c_plinit();
01149 }
01150 
01151 /*--------------------------------------------------------------------------*\
01152  * void plinit()
01153  *
01154  * Initializes PLplot, using preset or default options.
01155 \*--------------------------------------------------------------------------*/
01156 
01157 MZ_DLLEXPORT
01158 void
01159 c_plinit(void)
01160 {
01161     PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
01162     PLINT mk = 0, sp = 0, inc = 0, del = 2000;
01163 
01164     pllib_init();
01165 
01166     if (plsc->level != 0)
01167        plend1();
01168 
01169 /* Set stream number */
01170 
01171     plsc->ipls = ipls;
01172 
01173 /* Set up devices */
01174 
01175     pllib_devinit();
01176 
01177 /* Auxiliary stream setup */
01178 
01179     plstrm_init();
01180 
01181 /* Initialize device & first page */
01182 
01183     plP_init();
01184     plP_bop();
01185     plsc->level = 1;
01186 
01187 /* Calculate factor such that the character aspect ratio is preserved 
01188  * when the overall aspect ratio is changed, i.e., if portrait mode is
01189  * requested (only honored for subset of drivers) or if the aspect ratio
01190  * is specified in any way, or if a 90 deg rotation occurs with
01191  * -freeaspect. */
01192    
01193 /* Case where plsc->aspect has a value.... (e.g., -a aspect on the
01194  * command line or 2nd parameter of plsdidev specified) */
01195     if (plsc->aspect > 0.) {
01196        lx = plsc->phyxlen / plsc->xpmm;
01197        ly = plsc->phyylen / plsc->ypmm;
01198        aspect_old = lx / ly;
01199        aspect_new = plsc->aspect;
01200        plsc->caspfactor = sqrt(aspect_old/aspect_new);
01201     }
01202 /* Case of 90 deg rotations with -freeaspect (this is also how portraite
01203  * mode is implemented for the drivers that honor -portrait). */
01204     else if (plsc->freeaspect && ABS(cos(plsc->diorot * PI / 2.)) <= 1.e-5) {
01205        lx = plsc->phyxlen / plsc->xpmm;
01206        ly = plsc->phyylen / plsc->ypmm;
01207        aspect_old = lx / ly;
01208        aspect_new = ly / lx;
01209        plsc->caspfactor = sqrt(aspect_old/aspect_new);
01210     }
01211 
01212     else
01213        plsc->caspfactor = 1.;
01214 
01215 /* Load fonts */
01216 
01217     plsc->cfont = 1;
01218     plfntld(initfont);
01219 
01220 /* Set up subpages */
01221 
01222     plP_subpInit();
01223 
01224 /* Set up number of allowed digits before switching to scientific notation */
01225 /* The user can always change this */
01226 
01227     if (plsc->xdigmax == 0)
01228        plsc->xdigmax = 4;
01229 
01230     if (plsc->ydigmax == 0)
01231        plsc->ydigmax = 4;
01232 
01233     if (plsc->zdigmax == 0)
01234        plsc->zdigmax = 3;
01235 
01236 /* Switch to graphics mode and set color */
01237 
01238     plgra();
01239     plcol(1);
01240 
01241     plstyl(0, &mk, &sp);
01242     plpat(1, &inc, &del);
01243 
01244 /* Set clip limits. */
01245 
01246     plsc->clpxmi = plsc->phyxmi;
01247     plsc->clpxma = plsc->phyxma;
01248     plsc->clpymi = plsc->phyymi;
01249     plsc->clpyma = plsc->phyyma;
01250 
01251 /* Page aspect ratio. */
01252 
01253     lx = plsc->phyxlen / plsc->xpmm;
01254     ly = plsc->phyylen / plsc->ypmm;
01255     plsc->aspdev = lx / ly;
01256 
01257 /* Initialize driver interface */
01258 
01259     pldi_ini();
01260 
01261 /* Apply compensating factor to original xpmm and ypmm so that 
01262  * character aspect ratio is preserved when overall aspect ratio
01263  * is changed.  This must appear here in the code because previous
01264  * code in this routine and in routines that it calls must use the original
01265  * values of xpmm and ypmm before the compensating factor is applied.  */
01266 
01267     plP_gpixmm(&xpmm_loc, &ypmm_loc);
01268     plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor); 
01269 }
01270 
01271 /*--------------------------------------------------------------------------*\
01272  * void plend()
01273  *
01274  * End a plotting session for all open streams.
01275 \*--------------------------------------------------------------------------*/
01276 
01277 MZ_DLLEXPORT
01278 void
01279 c_plend(void)
01280 {
01281     PLINT i;
01282 
01283     for (i = PL_NSTREAMS-1; i >= 0; i--) {
01284        if (pls[i] != NULL) {
01285            plsstrm(i);
01286            c_plend1();
01287        }
01288     }
01289     plfontrel();
01290 #ifdef ENABLE_DYNDRIVERS
01291 /* Release the libltdl resources */
01292     lt_dlexit();
01293 #endif
01294 }
01295 
01296 /*--------------------------------------------------------------------------*\
01297  * void plend1()
01298  *
01299  * End a plotting session for the current stream only.  After the stream is
01300  * ended the memory associated with the stream's PLStream data structure is
01301  * freed (for stream > 0), and the stream counter is set to 0 (the default).
01302 \*--------------------------------------------------------------------------*/
01303 
01304 void
01305 c_plend1(void)
01306 {
01307     if (plsc->level > 0) {
01308        plP_eop();
01309        plP_tidy();
01310        plsc->level = 0;
01311     }
01312 
01313 /* Free all malloc'ed stream memory */
01314 
01315     free_mem(plsc->cmap0);
01316     free_mem(plsc->cmap1);
01317     free_mem(plsc->plwindow);
01318     free_mem(plsc->geometry);
01319     free_mem(plsc->dev);
01320     free_mem(plsc->BaseName);
01321 
01322 /* Free malloc'ed stream if not in initial stream, else clear it out */
01323 
01324     if (ipls > 0) {
01325        free_mem(plsc);
01326        pls[ipls] = NULL;
01327        plsstrm(0);
01328     }
01329     else {
01330        memset((char *) pls[ipls], 0, sizeof(PLStream));
01331     }
01332 }
01333 
01334 /*--------------------------------------------------------------------------*\
01335  * void plsstrm
01336  *
01337  * Set stream number.  If the data structure for a new stream is
01338  * unallocated, we allocate it here.
01339 \*--------------------------------------------------------------------------*/
01340 
01341 void
01342 c_plsstrm(PLINT strm)
01343 {
01344     if (strm < 0 || strm >= PL_NSTREAMS) {
01345        fprintf(stderr,
01346               "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
01347               (int) strm, PL_NSTREAMS);
01348     }
01349     else {
01350        ipls = strm;
01351        if (pls[ipls] == NULL) {
01352            pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
01353            if (pls[ipls] == NULL)
01354               plexit("plsstrm: Out of memory.");
01355 
01356            memset((char *) pls[ipls], 0, sizeof(PLStream));
01357        }
01358        plsc = pls[ipls];
01359        plsc->ipls = ipls;
01360     }
01361 }
01362 
01363 /*--------------------------------------------------------------------------*\
01364  * void plgstrm
01365  *
01366  * Get current stream number.
01367 \*--------------------------------------------------------------------------*/
01368 
01369 void
01370 c_plgstrm(PLINT *p_strm)
01371 {
01372     *p_strm = ipls;
01373 }
01374 
01375 /*--------------------------------------------------------------------------*\
01376  * void plmkstrm
01377  *
01378  * Creates a new stream and makes it the default.  Differs from using
01379  * plsstrm(), in that a free stream number is found, and returned.
01380  *
01381  * Unfortunately, I /have/ to start at stream 1 and work upward, since
01382  * stream 0 is preallocated.  One of the BIG flaws in the PLplot API is
01383  * that no initial, library-opening call is required.  So stream 0 must be
01384  * preallocated, and there is no simple way of determining whether it is
01385  * already in use or not.
01386 \*--------------------------------------------------------------------------*/
01387 
01388 void
01389 c_plmkstrm(PLINT *p_strm)
01390 {
01391     int i;
01392 
01393     for (i = 1; i < PL_NSTREAMS; i++) {
01394        if (pls[i] == NULL)
01395            break;
01396     }
01397 
01398     if (i == PL_NSTREAMS) {
01399        fprintf(stderr, "plmkstrm: Cannot create new stream\n");
01400        *p_strm = -1;
01401     }
01402     else {
01403        *p_strm = i;
01404        plsstrm(i);
01405     }
01406     plstrm_init();
01407 }
01408 
01409 /*--------------------------------------------------------------------------*\
01410  * void plstrm_init
01411  *
01412  * Does required startup initialization of a stream.  Should be called right
01413  * after creating one (for allocating extra memory, etc).  Users shouldn't
01414  * need to call this directly.
01415  *
01416  * This function can be called multiple times for a given stream, in which
01417  * case only the first call produces any effect.  For streams >= 1, which
01418  * are created dynamically, this is called by the routine that allocates
01419  * the stream.  Stream 0, which is preallocated, is much harder to deal with
01420  * because any of a number of different calls may be the first call to the
01421  * library.  This is handled by just calling plstrm_init() from every
01422  * function that might be called first.  Sucks, but it should work.
01423 \*--------------------------------------------------------------------------*/
01424 
01425 void
01426 plstrm_init(void)
01427 {
01428     if ( ! plsc->initialized) {
01429        plsc->initialized = 1;
01430 
01431        if (plsc->cmap0 == NULL)
01432            plscmap0n(0);
01433 
01434        if (plsc->cmap1 == NULL)
01435            plscmap1n(0);
01436     }
01437 }
01438 
01439 /*--------------------------------------------------------------------------*\
01440  * pl_cpcolor
01441  *
01442  * Utility to copy one PLColor to another.
01443 \*--------------------------------------------------------------------------*/
01444 
01445 void
01446 pl_cpcolor(PLColor *to, PLColor *from)
01447 {
01448     to->r = from->r;
01449     to->g = from->g;
01450     to->b = from->b;
01451 }
01452 
01453 /*--------------------------------------------------------------------------*\
01454  * void plcpstrm
01455  *
01456  * Copies state parameters from the reference stream to the current stream.
01457  * Tell driver interface to map device coordinates unless flags == 1.
01458  *
01459  * This function is used for making save files of selected plots (e.g.
01460  * from the TK driver).  After initializing, you can get a copy of the
01461  * current plot to the specified device by switching to this stream and
01462  * issuing a plcpstrm() and a plreplot(), with calls to plbop() and
01463  * pleop() as appropriate.  The plot buffer must have previously been
01464  * enabled (done automatically by some display drivers, such as X).
01465 \*--------------------------------------------------------------------------*/
01466 
01467 void
01468 c_plcpstrm(PLINT iplsr, PLINT flags)
01469 {
01470     int i;
01471     PLStream *plsr;
01472 
01473     plsr = pls[iplsr];
01474     if (plsr == NULL) {
01475        fprintf(stderr, "plcpstrm: stream %d not in use\n", (int) iplsr);
01476        return;
01477     }
01478 
01479 /* May be debugging */
01480 
01481     plsc->debug = plsr->debug;
01482 
01483 /* Plot buffer -- need to copy file pointer so that plreplot() works */
01484 /* This also prevents inadvertent writes into the plot buffer */
01485 
01486     plsc->plbufFile = plsr->plbufFile;
01487 
01488 /* Driver interface */
01489 /* Transformation must be recalculated in current driver coordinates */
01490 
01491     if (plsr->difilt & PLDI_PLT) 
01492        plsdiplt(plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax);
01493 
01494     if (plsr->difilt & PLDI_DEV)
01495        plsdidev(plsr->mar, plsr->aspect, plsr->jx, plsr->jy);
01496 
01497     if (plsr->difilt & PLDI_ORI)
01498        plsdiori(plsr->diorot);
01499 
01500 /* Map device coordinates */
01501 
01502     if ( ! (flags & 0x01)) {
01503        pldebug("plcpstrm", "mapping parameters: %d %d %d %d %f %f\n",
01504               plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
01505               plsr->xpmm, plsr->ypmm);
01506        plsdimap(plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
01507                plsr->xpmm, plsr->ypmm);
01508     }
01509 
01510 /* current color */
01511 
01512     pl_cpcolor(&plsc->curcolor, &plsr->curcolor);
01513 
01514 /* cmap 0 */
01515 
01516     plsc->icol0 = plsr->icol0;
01517     plsc->ncol0 = plsr->ncol0;
01518     if (plsc->cmap0 != NULL)
01519        free((void *) plsc->cmap0);
01520 
01521     plsc->cmap0 = (PLColor *) calloc(1, plsc->ncol0 * sizeof(PLColor));
01522     for (i = 0; i < plsc->ncol0; i++)
01523        pl_cpcolor(&plsc->cmap0[i], &plsr->cmap0[i]);
01524 
01525 /* cmap 1 */
01526 
01527     plsc->icol1 = plsr->icol1;
01528     plsc->ncol1 = plsr->ncol1;
01529     if (plsc->cmap1 != NULL)
01530        free((void *) plsc->cmap1);
01531 
01532     plsc->cmap1 = (PLColor *) calloc(1, plsc->ncol1 * sizeof(PLColor));
01533     for (i = 0; i < plsc->ncol1; i++) 
01534        pl_cpcolor(&plsc->cmap1[i], &plsr->cmap1[i]);
01535 
01536 /* Initialize if it hasn't been done yet. */
01537 
01538     if (plsc->level == 0)
01539        plinit();
01540 }
01541 
01542 /*--------------------------------------------------------------------------*\
01543  * pllib_devinit()
01544  *
01545  * Does preliminary setup of device driver.
01546  *
01547  * This function (previously plGetDev) used to be what is now shown as
01548  * plSelectDev below.  However, the situation is a bit more complicated now in
01549  * the dynloadable drivers era.  We now have to:
01550  *
01551  * 1) Make sure the dispatch table is initialized to the union of static
01552  *    drivers and available dynamic drivers (done from pllib_init now).
01553  * 2) Allow the user to select the desired device.
01554  * 3) Initialize the dispatch table entries for the selected device, in the
01555  *    case that it is a dynloadable driver that has not yet been loaded.
01556  *
01557  * Also made non-static, in order to allow some device calls to be made prior
01558  * to calling plinit().  E.g. plframe needs to tell the X driver to create its
01559  * internal data structure during widget construction time (using the escape
01560  * function), but doesn't call plinit() until the plframe is actually mapped.
01561 \*--------------------------------------------------------------------------*/
01562 
01563 void
01564 pllib_devinit()
01565 {
01566     if (plsc->dev_initialized) return;
01567     plsc->dev_initialized = 1;
01568 
01569     plSelectDev();
01570 
01571     plLoadDriver();
01572 
01573 /* offset by one since table is zero-based, but input list is not */
01574     plsc->dispatch_table = dispatch_table[plsc->device - 1];
01575 }
01576 
01577 #ifdef ENABLE_DYNDRIVERS
01578 
01579 static char*
01580 plGetDrvDir ()
01581 {
01582     char* drvdir;
01583 
01584 /* Get drivers directory in PLPLOT_DRV_DIR or DATA_DIR/DRV_DIR, 
01585  *  on this order
01586  */
01587  
01588     pldebug("plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n");
01589     drvdir = getenv ("PLPLOT_DRV_DIR");
01590 
01591     if (drvdir == NULL) {
01592         pldebug("plGetDrvDir", 
01593                "Will use drivers dir: " DATA_DIR "/" DRV_DIR "\n");
01594         drvdir = DATA_DIR "/" DRV_DIR;
01595     }
01596     
01597     return drvdir;
01598 }    
01599 
01600 #endif
01601 
01602 
01603 /*--------------------------------------------------------------------------*\
01604  * void plInitDispatchTable()
01605  *
01606  * ...
01607 \*--------------------------------------------------------------------------*/
01608 
01609 static int plDispatchSequencer( const void *p1, const void *p2 )
01610 {
01611     const PLDispatchTable* t1 = *(PLDispatchTable **) p1;
01612     const PLDispatchTable* t2 = *(PLDispatchTable **) p2;
01613 
01614 /*     printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n", */
01615 /*             t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq ); */
01616 
01617     return t1->pl_seq - t2->pl_seq;
01618 }
01619 
01620 static void
01621 plInitDispatchTable()
01622 {
01623     int n;
01624 
01625 #ifdef ENABLE_DYNDRIVERS
01626     char buf[300];
01627     char* drvdir;
01628     char *devnam, *devdesc, *devtype, *driver, *tag, *seqstr;
01629     int seq;
01630     int i, j, driver_found, done=0;
01631     FILE *fp_drvdb = NULL;
01632     DIR* dp_drvdir = NULL;
01633     struct dirent* entry;
01634     lt_dlhandle dlhand;
01635 
01636 /* Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings
01637    will be stored */
01638     fp_drvdb = tmpfile ();
01639 
01640 /* Open the drivers directory */
01641     drvdir = plGetDrvDir ();
01642     dp_drvdir = opendir (drvdir);
01643     if (dp_drvdir == NULL)
01644       plabort ("plInitDispatchTable: Could not open drivers directory");
01645 
01646 /* Loop over each entry in the drivers directory */
01647 
01648     pldebug ("plInitDispatchTable", "Scanning dyndrivers dir\n");
01649     while ((entry = readdir (dp_drvdir)) != NULL) 
01650     {
01651         char* name = entry->d_name;
01652         int len = strlen (name) - 3;
01653 
01654             pldebug ("plInitDispatchTable", 
01655                      "Consider file %s\n", name);
01656 
01657 /* Only consider entries that have the ".rc" suffix */
01658        if ((len > 0) && (strcmp (name + len, ".rc") == 0)) {
01659            char path[300];
01660            char buf[300];
01661             FILE* fd;
01662         
01663 /* Open the driver's info file */
01664             sprintf (path, "%s/%s", drvdir, name);
01665             fd = fopen (path, "r");
01666             if (fd == NULL) {
01667                sprintf (buf,
01668                   "plInitDispatchTable: Could not open driver info file %s\n",
01669                   name);
01670                plabort (buf);
01671            }
01672 
01673 /* Each line in the <driver>.rc file corresponds to a specific device.
01674  * Write it to the drivers db file and take care of leading newline 
01675  * character */
01676  
01677             pldebug ("plInitDispatchTable", 
01678                      "Opened driver info file %s\n", name);
01679             while (fgets (buf, 300, fd) != NULL) 
01680            {
01681                 fprintf (fp_drvdb, "%s", buf);
01682               if ( buf [strlen (buf) - 1] != '\n' )
01683                   fprintf (fp_drvdb, "\n");
01684                 npldynamicdevices++;
01685            }
01686            fclose (fd);
01687        }
01688     }
01689     
01690 /* Make sure that the temporary file containing the driversr database 
01691  * is ready to read and close the directory handle */
01692     fflush (fp_drvdb);
01693     closedir (dp_drvdir);
01694 
01695 #endif
01696 
01697 /* Allocate space for the dispatch table. */
01698     dispatch_table = (PLDispatchTable **) 
01699        malloc( (nplstaticdevices + npldynamicdevices) * sizeof(PLDispatchTable *) );
01700 
01701 /* Initialize the dispatch table entries for the static devices by calling
01702    the dispatch table initialization function for each static device.  This
01703    is the same function that would be called at load time for dynamic
01704    drivers. */
01705 
01706     for( n=0; n < nplstaticdevices; n++ )
01707     {
01708         dispatch_table[n] = (PLDispatchTable *)malloc( sizeof(PLDispatchTable) );
01709 
01710         (*static_device_initializers[n])( dispatch_table[n] );
01711     }
01712     npldrivers = nplstaticdevices;
01713 
01714 #ifdef ENABLE_DYNDRIVERS
01715 
01716 /* Allocate space for the device and driver specs.  We may not use all of
01717  * these driver descriptors, but we obviously won't need more drivers than
01718  * devices... */
01719     loadable_device_list = malloc( npldynamicdevices * sizeof(PLLoadableDevice) );
01720     loadable_driver_list = malloc( npldynamicdevices * sizeof(PLLoadableDriver) );
01721 
01722     rewind( fp_drvdb );
01723 
01724     i = 0;
01725     done = !(i < npldynamicdevices);
01726     while( !done ) {
01727         char *p = fgets( buf, 300, fp_drvdb );
01728 
01729         if (p == 0) {
01730             done = 1;
01731             continue;
01732         }
01733 
01734         devnam  = strtok( buf, ":" );
01735         devdesc = strtok( 0, ":" );
01736         devtype = strtok( 0, ":" );
01737         driver  = strtok( 0, ":" );
01738         seqstr  = strtok( 0, ":" );
01739         tag     = strtok( 0, "\n" );
01740 
01741         seq     = atoi(seqstr);
01742 
01743         n = npldrivers++;
01744 
01745         dispatch_table[n] = malloc( sizeof(PLDispatchTable) );
01746 
01747     /* Fill in the dispatch table entries. */
01748         dispatch_table[n]->pl_MenuStr = plstrdup(devdesc);
01749         dispatch_table[n]->pl_DevName = plstrdup(devnam);
01750         dispatch_table[n]->pl_type = atoi(devtype);
01751         dispatch_table[n]->pl_seq = seq;
01752         dispatch_table[n]->pl_init = 0;
01753         dispatch_table[n]->pl_line = 0;
01754         dispatch_table[n]->pl_polyline = 0;
01755         dispatch_table[n]->pl_eop = 0;
01756         dispatch_table[n]->pl_bop = 0;
01757         dispatch_table[n]->pl_tidy = 0;
01758         dispatch_table[n]->pl_state = 0;
01759         dispatch_table[n]->pl_esc = 0;
01760 
01761     /* Add a record to the loadable device list */
01762         loadable_device_list[i].devnam = plstrdup(devnam);
01763         loadable_device_list[i].description = plstrdup(devdesc);
01764         loadable_device_list[i].drvnam = plstrdup(driver);
01765         loadable_device_list[i].tag = plstrdup(tag);
01766 
01767     /* Now see if this driver has been seen before.  If not, add a driver
01768      * entry for it. */
01769         driver_found = 0;
01770         for( j=0; j < nloadabledrivers; j++ )
01771             if (strcmp( driver, loadable_driver_list[j].drvnam) == 0)
01772             {
01773                 driver_found = 1;
01774                 break;
01775             }
01776 
01777         if (!driver_found)
01778         {
01779             loadable_driver_list[nloadabledrivers].drvnam = plstrdup(driver);
01780             loadable_driver_list[nloadabledrivers].dlhand = 0;
01781             nloadabledrivers++;
01782         }
01783 
01784         loadable_device_list[i].drvidx = j;
01785 
01786     /* Get ready for next loadable device spec */
01787         i++;
01788     }
01789     
01790 /* RML: close fp_drvdb */
01791     fclose (fp_drvdb);
01792 
01793 #endif
01794 
01795 /* Finally, we need to sort the list into presentation order, based on the
01796    sequence number in the dispatch ttable entries. */
01797 
01798     qsort( dispatch_table, npldrivers, sizeof(PLDispatchTable*),
01799            plDispatchSequencer );
01800 }
01801 
01802 /*--------------------------------------------------------------------------*\
01803  * void plSelectDev()
01804  *
01805  * If the user has not already specified the output device, or the
01806  * one specified is either: (a) not available, (b) "?", or (c) NULL, the
01807  * user is prompted for it.
01808  *
01809  * Prompting quits after 10 unsuccessful tries in case the user has
01810  * run the program in the background with insufficient input.
01811 \*--------------------------------------------------------------------------*/
01812 
01813 static void
01814 plSelectDev()
01815 {
01816     int dev, i, count, length;
01817     char response[80];
01818 
01819 /* Device name already specified.  See if it is valid. */
01820 
01821     if (*(plsc->DevName) != '\0' && *(plsc->DevName) != '?') {
01822        length = strlen(plsc->DevName);
01823        for (i = 0; i < npldrivers; i++) {
01824            if ((*plsc->DevName == *dispatch_table[i]->pl_DevName) &&
01825               (strncmp(plsc->DevName,
01826                       dispatch_table[i]->pl_DevName, length) == 0))
01827               break;
01828        }
01829        if (i < npldrivers) {
01830            plsc->device = i + 1;
01831            return;
01832        }
01833        else {
01834            fprintf(stderr, "Requested device %s not available\n",
01835                   plsc->DevName);
01836        }
01837     }
01838 
01839     dev = 0;
01840     count = 0;
01841 
01842     if (npldrivers == 1)
01843        dev = 1;
01844 
01845 /* User hasn't specified it correctly yet, so we prompt */
01846 
01847     while (dev < 1 || dev > npldrivers) {
01848        fprintf(stdout, "\nPlotting Options:\n");
01849        for (i = 0; i < npldrivers; i++) {
01850            fprintf(stdout, " <%2d> %-10s %s\n", i + 1,
01851                   dispatch_table[i]->pl_DevName,
01852                   dispatch_table[i]->pl_MenuStr);
01853        }
01854        if (ipls == 0)
01855            fprintf(stdout, "\nEnter device number or keyword: ");
01856        else
01857            fprintf(stdout, "\nEnter device number or keyword (stream %d): ",
01858                  (int) ipls);
01859 
01860        fgets(response, sizeof(response), stdin);
01861 
01862     /* First check to see if device keyword was entered. */
01863     /* Final "\n" in response messes things up, so ignore it.  */
01864 
01865        length = strlen(response);
01866        if (*(response - 1 + length) == '\n')
01867            length--;
01868 
01869        for (i = 0; i < npldrivers; i++) {
01870            if ( ! strncmp(response, dispatch_table[i]->pl_DevName,
01871                         (unsigned int) length))
01872               break;
01873        }
01874        if (i < npldrivers) {
01875            dev = i + 1;
01876        }
01877        else {
01878            if ((dev = atoi(response)) < 1) {
01879               fprintf(stdout, "\nInvalid device: %s", response);
01880               dev = 0;
01881            }
01882        }
01883        if (count++ > 10)
01884            plexit("plSelectDev: Too many tries.");
01885     }
01886     plsc->device = dev;
01887     strcpy(plsc->DevName, dispatch_table[dev - 1]->pl_DevName);
01888 }
01889 
01890 /*--------------------------------------------------------------------------*\
01891  * void plLoadDriver()
01892  *
01893  * Make sure the selected driver is loaded.  Static drivers are already
01894  * loaded, but if the user selected a dynamically loadable driver, we may
01895  * have to take care of that now.
01896 \*--------------------------------------------------------------------------*/
01897 
01898 static void
01899 plLoadDriver(void)
01900 {
01901 #ifdef ENABLE_DYNDRIVERS
01902     int i, drvidx;
01903     char sym[60];
01904     char *tag;
01905 
01906     int n=plsc->device - 1;
01907     PLDispatchTable *dev = dispatch_table[n];
01908     PLLoadableDriver *driver = 0;
01909 
01910 /* If the dispatch table is already filled in, then either the device was
01911  * linked in statically, or else perhaps it was already loaded.  In either
01912  * case, we have nothing left to do. */
01913     if (dev->pl_init)
01914         return;
01915 
01916     pldebug("plLoadDriver", "Device not loaded!\n");
01917 
01918 /* Now search through the list of loadable devices, looking for the record
01919  * that corresponds to the requested device. */
01920     for( i=0; i < npldynamicdevices; i++ )
01921         if (strcmp( dev->pl_DevName, loadable_device_list[i].devnam ) == 0)
01922             break;
01923 
01924 /* If we couldn't find such a record, then there is some sort of internal
01925  * logic flaw since plSelectDev is supposed to only select a valid device.
01926  */
01927     if (i == npldynamicdevices) {
01928         fprintf( stderr, "No such device: %s.\n", dev->pl_DevName );
01929         plexit("plLoadDriver detected device logic screwup");
01930     }
01931 
01932 /* Note the device tag, and the driver index. Note that a given driver could
01933  * supply multiple devices, each with a unique tag to distinguish the driver
01934  * entry points for the differnet supported devices. */
01935     tag = loadable_device_list[i].tag;
01936     drvidx = loadable_device_list[i].drvidx;
01937 
01938     pldebug("plLoadDriver", "tag=%s, drvidx=%d\n", tag, drvidx ); 
01939 
01940     driver = &loadable_driver_list[drvidx];
01941 
01942 /* Load the driver if it hasn't been loaded yet. */
01943     if (!driver->dlhand)
01944     {
01945         char drvspec[ 400 ];
01946         sprintf( drvspec, "%s/%s", plGetDrvDir (), driver->drvnam );
01947 
01948        pldebug("plLoadDriver", "Trying to load %s on %s\n",
01949               driver->drvnam, drvspec );
01950 
01951         driver->dlhand = lt_dlopenext( drvspec);
01952     }
01953 
01954 /* If it still isn't loaded, then we're doomed. */
01955     if (!driver->dlhand)
01956     {
01957         pldebug("plLoadDriver", "lt_dlopenext failed because of "
01958                "the following reason:\n%s\n", lt_dlerror ());
01959         fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam );
01960         plexit("Unable to load driver");
01961     }
01962 
01963 /* Now we are ready to ask the driver's device dispatch init function to
01964    initialize the entries in the dispatch table. */
01965 
01966     sprintf( sym, "plD_dispatch_init_%s", tag );
01967     {
01968         PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym );
01969         if (!dispatch_init)
01970         {
01971             fprintf( stderr,
01972                      "Unable to locate dispatch table initialization function for driver: %s.\n", 
01973                    driver->drvnam );
01974             return;
01975         }
01976 
01977         (*dispatch_init)( dev );
01978     }
01979 #endif
01980 }
01981 
01982 /*--------------------------------------------------------------------------*\
01983  * void plfontld()
01984  *
01985  * Load specified font set.
01986 \*--------------------------------------------------------------------------*/
01987 
01988 void
01989 c_plfontld(PLINT ifont)
01990 {
01991     if (ifont != 0)
01992        ifont = 1;
01993 
01994     if (plsc->level > 0)
01995        plfntld(ifont);
01996     else
01997        initfont = ifont;
01998 }
01999 
02000 /*--------------------------------------------------------------------------*\
02001  * void plreplot()
02002  *
02003  * Replays contents of plot buffer to current device/file.
02004 \*--------------------------------------------------------------------------*/
02005 
02006 void
02007 c_plreplot(void)
02008 {
02009     if (plsc->plbufFile != NULL) {
02010        plRemakePlot(plsc);
02011     }
02012     else {
02013        plwarn("plreplot: plot buffer not available");
02014     }
02015 }
02016 
02017 /*--------------------------------------------------------------------------*\
02018  * void plgFileDevs()
02019  *
02020  * Returns a list of file-oriented device names and their menu strings,
02021  * for use in a graphical interface.  The caller must allocate enough
02022  * space for (*p_menustr) and (*p_devname) to hold a pointer for each
02023  * device -- 20 or so is plenty.  E.g. char *menustr[20].  The size of
02024  * these arrays should be passed in *p_ndev, which, on exit, holds the
02025  * number of devices actually present.
02026 \*--------------------------------------------------------------------------*/
02027 
02028 void
02029 plgFileDevs(char ***p_menustr, char ***p_devname, int *p_ndev)
02030 {
02031     plgdevlst(*p_menustr, *p_devname, p_ndev, 0);
02032 }
02033 
02034 /*--------------------------------------------------------------------------*\
02035  * void plgDevs()
02036  *
02037  * Like plgFileDevs(), but returns names and menu strings for all devices.
02038 \*--------------------------------------------------------------------------*/
02039 
02040 void
02041 plgDevs(char ***p_menustr, char ***p_devname, int *p_ndev)
02042 {
02043     plgdevlst(*p_menustr, *p_devname, p_ndev, -1);
02044 }
02045 
02046 static void
02047 plgdevlst(char **p_menustr, char **p_devname, int *p_ndev, int type)
02048 {
02049     int i, j;
02050 
02051     pllib_init();
02052 
02053     for (i = j = 0; i < npldrivers; i++) {
02054        if (type < 0 || dispatch_table[i]->pl_type == type) {
02055            p_menustr[j] = dispatch_table[i]->pl_MenuStr;
02056            p_devname[j] = dispatch_table[i]->pl_DevName;
02057            if (++j + 1 >= *p_ndev) {
02058                plwarn("plgdevlst:  too many devices");
02059               break;
02060              }
02061        }
02062     }
02063     p_menustr[j] = NULL;
02064     p_devname[j] = NULL;
02065     *p_ndev = j;
02066 }
02067 
02068 /*--------------------------------------------------------------------------*\
02069  *  Various external access routines.
02070 \*--------------------------------------------------------------------------*/
02071 
02072 /* Get output device parameters. */
02073 
02074 void
02075 c_plgpage(PLFLT *p_xp, PLFLT *p_yp,
02076          PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff)
02077 {
02078     *p_xp = plsc->xdpi;
02079     *p_yp = plsc->ydpi;
02080     *p_xleng = plsc->xlength;
02081     *p_yleng = plsc->ylength;
02082     *p_xoff = plsc->xoffset;
02083     *p_yoff = plsc->yoffset;
02084 }
02085 
02086 /* Set output device parameters.  Usually ignored by the driver. */
02087 
02088 MZ_DLLEXPORT
02089 void
02090 c_plspage(PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff)
02091 {
02092     if (xp)
02093        plsc->xdpi = xp;
02094     if (yp)
02095        plsc->ydpi = yp;
02096 
02097     if (xleng)
02098        plsc->xlength = xleng;
02099     if (yleng)
02100        plsc->ylength = yleng;
02101 
02102     if (xoff)
02103        plsc->xoffset = xoff;
02104     if (yoff)
02105        plsc->yoffset = yoff;
02106 
02107     plsc->pageset = 1;
02108 }
02109 
02110 /* Set the number of subwindows in x and y */
02111 
02112 void
02113 c_plssub(PLINT nx, PLINT ny)
02114 {
02115     if (nx > 0)
02116        plsc->nsubx = nx;
02117     if (ny > 0)
02118        plsc->nsuby = ny;
02119 
02120 /* Force a page advance */
02121 
02122     if (plsc->level > 0) {
02123         plP_subpInit();
02124 /*AWI  plP_eop();
02125        plP_bop();*/
02126     }
02127 }
02128 
02129 /* Set the device (keyword) name */
02130 
02131 MZ_DLLEXPORT
02132 void
02133 c_plsdev(const char *devname)
02134 {
02135     if (plsc->level > 0) {
02136        plwarn("plsdev: Must be called before plinit.");
02137        return;
02138     }
02139     if (devname != NULL) {
02140        strncpy(plsc->DevName, devname, sizeof(plsc->DevName) - 1);
02141        plsc->DevName[sizeof(plsc->DevName) - 1] = '\0';
02142     }
02143 }
02144 
02145 /* Get the current device (keyword) name */
02146 /* Note: you MUST have allocated space for this (80 characters is safe) */
02147 
02148 void
02149 c_plgdev(char *p_dev)
02150 {
02151     strcpy(p_dev, plsc->DevName);
02152 }
02153 
02154 /* Set the memory area to be plotted (with the 'mem' driver) as the 'dev'
02155    member of the stream structure.  Also set the number
02156    of pixels in the memory passed in in 'plotmem'.
02157    Plotmem is a block of memory maxy by maxx by 3 bytes long, say:
02158    480 x 640 x 3 (Y, X, RGB)
02159 
02160    This memory will be freed by the user!
02161 */
02162 
02163 void
02164 c_plsmem(PLINT maxx, PLINT maxy, void *plotmem)
02165 {
02166     plsc->dev = plotmem;
02167     plP_setphy (0, maxx, 0, maxy);
02168 }
02169 
02170 /* Get the current stream pointer */
02171 
02172 void
02173 plgpls(PLStream **p_pls)
02174 {
02175     *p_pls = plsc;
02176 }
02177 
02178 /* Get the (current) run level. 
02179  * Valid settings are:
02180  *   0 uninitialized 
02181  *   1 initialized
02182  *   2 viewport defined
02183  *   3 world coords defined 
02184  */
02185 
02186 void
02187 c_plglevel(PLINT *p_level)
02188 {
02189     *p_level = plsc->level;
02190 }
02191 
02192 /* Set the function pointer for the keyboard event handler */
02193 
02194 void
02195 plsKeyEH(void (*KeyEH) (PLGraphicsIn *, void *, int *),
02196         void *KeyEH_data)
02197 {
02198     plsc->KeyEH = KeyEH;
02199     plsc->KeyEH_data = KeyEH_data;
02200 }
02201 
02202 /* Set the function pointer for the (mouse) button event handler */
02203 
02204 void
02205 plsButtonEH(void (*ButtonEH) (PLGraphicsIn *, void *, int *),
02206            void *ButtonEH_data)
02207 {
02208     plsc->ButtonEH = ButtonEH;
02209     plsc->ButtonEH_data = ButtonEH_data;
02210 }
02211 
02212 /* Sets an optional user bop handler. */
02213 
02214 void
02215 plsbopH(void (*handler) (void *, int *), void *handler_data)
02216 {
02217     plsc->bop_handler = handler;
02218     plsc->bop_data = handler_data;
02219 }
02220 
02221 /* Sets an optional user eop handler. */
02222 
02223 void
02224 plseopH(void (*handler) (void *, int *), void *handler_data)
02225 {
02226     plsc->eop_handler = handler;
02227     plsc->eop_data = handler_data;
02228 }
02229 
02230 /* Set the variables to be used for storing error info */
02231 
02232 void
02233 plsError(PLINT *errcode, char *errmsg)
02234 {
02235     if (errcode != NULL)
02236        plsc->errcode = errcode;
02237 
02238     if (errmsg != NULL)
02239        plsc->errmsg = errmsg;
02240 }
02241 
02242 /* Set orientation.  Must be done before calling plinit. */
02243 
02244 void
02245 c_plsori(PLINT ori)
02246 {
02247     plsdiori((PLFLT) ori);
02248 }
02249 
02250 /*
02251  * Set pen width.  Can be done any time, but before calling plinit is best
02252  * since otherwise it may be volatile (i.e. reset on next page advance). 
02253  * If width < 0 or is unchanged by the call, nothing is done.
02254  */
02255 
02256 MZ_DLLEXPORT
02257 void
02258 c_plwid(PLINT width)
02259 {
02260     if (width != plsc->width && width >= 0) {
02261        plsc->width = width;
02262 
02263        if (plsc->level > 0) {
02264            if ( ! plsc->widthlock) 
02265               plP_state(PLSTATE_WIDTH);
02266        }
02267     }
02268 }
02269 
02270 /* Set the output file pointer */
02271 
02272 void
02273 plgfile(FILE **p_file)
02274 {
02275     *p_file = plsc->OutFile;
02276 }
02277 
02278 /* Get the output file pointer */
02279 
02280 void
02281 plsfile(FILE *file)
02282 {
02283     plsc->OutFile = file;
02284 }
02285 
02286 /* Get the (current) output file name.  Must be preallocated to >=80 bytes */
02287 /* Beyond that, I truncate it.  You have been warned. */
02288 
02289 void
02290 c_plgfnam(char *fnam)
02291 {
02292     if (fnam == NULL) {
02293        plabort("filename string must be preallocated to >=80 bytes");
02294        return;
02295     }
02296 
02297     *fnam = '\0';
02298     if (plsc->FileName != NULL) {
02299        strncpy(fnam, plsc->FileName, 79);
02300        fnam[79] = '\0';
02301     }
02302 }
02303 
02304 /* Set the output file name. */
02305 
02306 MZ_DLLEXPORT
02307 void
02308 c_plsfnam(const char *fnam)
02309 {
02310     plP_sfnam(plsc, fnam);
02311 }
02312 
02313 /* Set the pause (on end-of-page) status */
02314 
02315 void
02316 c_plspause(PLINT pause)
02317 {
02318     plsc->nopause = ! pause;
02319 }
02320 
02321 /* Set the floating point precision (in number of places) in numeric labels. */
02322 
02323 void
02324 c_plprec(PLINT setp, PLINT prec)
02325 {
02326     plsc->setpre = setp;
02327     plsc->precis = prec;
02328 }
02329 
02330 /* Get the floating point precision (in number of places) in numeric labels. */
02331 
02332 void
02333 plP_gprec(PLINT *p_setp, PLINT *p_prec)
02334 {
02335     *p_setp = plsc->setpre;
02336     *p_prec = plsc->precis;
02337 }
02338 
02339 /*
02340  * Set the escape character for text strings.
02341  * From C you can pass as a character, from Fortran it needs to be the decimal
02342  * ASCII value.  Only selected characters are allowed to prevent the user from
02343  * shooting himself in the foot (a '\' isn't allowed since it conflicts with
02344  * C's use of backslash as a character escape).
02345  */
02346 
02347 void
02348 c_plsesc(char esc)
02349 {
02350     switch (esc) {
02351        case '!':            /* ASCII 33 */
02352        case '#':            /* ASCII 35 */
02353        case '$':            /* ASCII 36 */
02354        case '%':            /* ASCII 37 */
02355        case '&':            /* ASCII 38 */
02356        case '*':            /* ASCII 42 */
02357        case '@':            /* ASCII 64 */
02358        case '^':            /* ASCII 94 */
02359        case '~':            /* ASCII 126 */
02360        plsc->esc = esc;
02361        break;
02362 
02363       default:
02364        plwarn("plsesc: Invalid escape character, ignoring.");
02365     }
02366 }
02367 
02368 /* Get the escape character for text strings. */
02369 
02370 void
02371 plgesc(char *p_esc)
02372 {
02373     if (plsc->esc == '\0')
02374        plsc->esc = '#';
02375 
02376     *p_esc = plsc->esc;
02377 }
02378 
02379 /* Get the current library version number */
02380 /* Note: you MUST have allocated space for this (80 characters is safe) */
02381 
02382 void
02383 c_plgver(char *p_ver)
02384 {
02385     strcpy(p_ver, VERSION);
02386 }
02387 
02388 /* Set inferior X window */
02389 
02390 void
02391 plsxwin(PLINT window_id)
02392 {
02393     plsc->window_id = window_id;
02394 }
02395 
02396 /*--------------------------------------------------------------------------*\
02397  *  These set/get information for family files, and may be called prior
02398  *  to plinit to set up the necessary parameters.  Arguments:
02399  *
02400  *     fam    familying flag (boolean)
02401  *     num    member number
02402  *     bmax   maximum member size
02403 \*--------------------------------------------------------------------------*/
02404 
02405 /* Get family file parameters */
02406 
02407 void
02408 c_plgfam(PLINT *p_fam, PLINT *p_num, PLINT *p_bmax)
02409 {
02410     *p_fam = plsc->family;
02411     *p_num = plsc->member;
02412     *p_bmax = plsc->bytemax;
02413 }
02414 
02415 /* Set family file parameters */
02416 
02417 void
02418 c_plsfam(PLINT fam, PLINT num, PLINT bmax)
02419 {
02420     if (plsc->level > 0)
02421        plwarn("plsfam: Must be called before plinit.");
02422 
02423     if (fam >= 0)
02424        plsc->family = fam;
02425     if (num >= 0)
02426        plsc->member = num;
02427     if (bmax >= 0)
02428        plsc->bytemax = bmax;
02429 }
02430 
02431 /* Advance to the next family file on the next new page */
02432 
02433 void
02434 c_plfamadv(void)
02435 {
02436     plsc->famadv = 1;
02437 }
02438 
02439 /*--------------------------------------------------------------------------*\
02440  *  Interface routines for axis labling parameters.
02441  *  See pldtik.c for more info.
02442 \*--------------------------------------------------------------------------*/
02443 
02444 /* Get x axis labeling parameters */
02445 
02446 void
02447 c_plgxax(PLINT *p_digmax, PLINT *p_digits)
02448 {
02449     *p_digmax = plsc->xdigmax;
02450     *p_digits = plsc->xdigits;
02451 }
02452 
02453 /* Set x axis labeling parameters */
02454 
02455 void
02456 c_plsxax(PLINT digmax, PLINT digits)
02457 {
02458     plsc->xdigmax = digmax;
02459     plsc->xdigits = digits;
02460 }
02461 
02462 /* Get y axis labeling parameters */
02463 
02464 void
02465 c_plgyax(PLINT *p_digmax, PLINT *p_digits)
02466 {
02467     *p_digmax = plsc->ydigmax;
02468     *p_digits = plsc->ydigits;
02469 }
02470 
02471 /* Set y axis labeling parameters */
02472 
02473 void
02474 c_plsyax(PLINT digmax, PLINT digits)
02475 {
02476     plsc->ydigmax = digmax;
02477     plsc->ydigits = digits;
02478 }
02479 
02480 /* Get z axis labeling parameters */
02481 
02482 void
02483 c_plgzax(PLINT *p_digmax, PLINT *p_digits)
02484 {
02485     *p_digmax = plsc->zdigmax;
02486     *p_digits = plsc->zdigits;
02487 }
02488 
02489 /* Set z axis labeling parameters */
02490 
02491 void
02492 c_plszax(PLINT digmax, PLINT digits)
02493 {
02494     plsc->zdigmax = digmax;
02495     plsc->zdigits = digits;
02496 }
02497 
02498 /* Get character default height and current (scaled) height */
02499 
02500 void
02501 c_plgchr(PLFLT *p_def, PLFLT *p_ht)
02502 {
02503     *p_def = plsc->chrdef;
02504     *p_ht = plsc->chrht;
02505 }
02506 
02507 /* Get viewport boundaries in normalized device coordinates */
02508 
02509 void
02510 c_plgvpd(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
02511 {
02512     *p_xmin = plsc->vpdxmi;
02513     *p_xmax = plsc->vpdxma;
02514     *p_ymin = plsc->vpdymi;
02515     *p_ymax = plsc->vpdyma;
02516 }
02517 
02518 /* Get viewport boundaries in world coordinates */
02519 
02520 void
02521 c_plgvpw(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
02522 {
02523     *p_xmin = plsc->vpwxmi;
02524     *p_xmax = plsc->vpwxma;
02525     *p_ymin = plsc->vpwymi;
02526     *p_ymax = plsc->vpwyma;
02527 }
02528 
02529 /*--------------------------------------------------------------------------*\
02530  *  These should not be called by the user.
02531 \*--------------------------------------------------------------------------*/
02532 
02533 /* Get x-y domain in world coordinates for 3d plots */
02534 
02535 void
02536 plP_gdom(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
02537 {
02538     *p_xmin = plsc->domxmi;
02539     *p_xmax = plsc->domxma;
02540     *p_ymin = plsc->domymi;
02541     *p_ymax = plsc->domyma;
02542 }
02543 
02544 /* Get vertical (z) scale parameters for 3-d plot */
02545 
02546 void
02547 plP_grange(PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax)
02548 {
02549     *p_zscl = plsc->zzscl;
02550     *p_zmin = plsc->ranmi;
02551     *p_zmax = plsc->ranma;
02552 }
02553 
02554 /* Get parameters used in 3d plots */
02555 
02556 void
02557 plP_gw3wc(PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz)
02558 {
02559     *p_dxx = plsc->cxx;
02560     *p_dxy = plsc->cxy;
02561     *p_dyx = plsc->cyx;
02562     *p_dyy = plsc->cyy;
02563     *p_dyz = plsc->cyz;
02564 }
02565 
02566 /* Get clip boundaries in physical coordinates */
02567 
02568 void
02569 plP_gclp(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
02570 {
02571     *p_ixmin = plsc->clpxmi;
02572     *p_ixmax = plsc->clpxma;
02573     *p_iymin = plsc->clpymi;
02574     *p_iymax = plsc->clpyma;
02575 }
02576 
02577 /* Set clip boundaries in physical coordinates */
02578 
02579 void
02580 plP_sclp(PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax)
02581 {
02582     plsc->clpxmi = ixmin;
02583     plsc->clpxma = ixmax;
02584     plsc->clpymi = iymin;
02585     plsc->clpyma = iymax;
02586 }
02587 
02588 /* Get physical device limits in physical coordinates */
02589 
02590 void
02591 plP_gphy(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
02592 {
02593     *p_ixmin = plsc->phyxmi;
02594     *p_ixmax = plsc->phyxma;
02595     *p_iymin = plsc->phyymi;
02596     *p_iymax = plsc->phyyma;
02597 }
02598 
02599 /* Get number of subpages on physical device and current subpage */
02600 
02601 void
02602 plP_gsub(PLINT *p_nx, PLINT *p_ny, PLINT *p_cs)
02603 {
02604     *p_nx = plsc->nsubx;
02605     *p_ny = plsc->nsuby;
02606     *p_cs = plsc->cursub;
02607 }
02608 
02609 /* Set number of subpages on physical device and current subpage */
02610 
02611 void
02612 plP_ssub(PLINT nx, PLINT ny, PLINT cs)
02613 {
02614     plsc->nsubx = nx;
02615     plsc->nsuby = ny;
02616     plsc->cursub = cs;
02617 }
02618 
02619 /* Get number of pixels to a millimeter */
02620 
02621 void
02622 plP_gpixmm(PLFLT *p_x, PLFLT *p_y)
02623 {
02624     *p_x = plsc->xpmm;
02625     *p_y = plsc->ypmm;
02626 }
02627 
02628 /* All the drivers call this to set physical pixels/mm. */
02629 
02630 void
02631 plP_setpxl(PLFLT xpmm, PLFLT ypmm)
02632 {
02633     plsc->xpmm = xpmm;
02634     plsc->ypmm = ypmm;
02635     plsc->umx = 1000.0 / plsc->xpmm;
02636     plsc->umy = 1000.0 / plsc->ypmm;
02637 }
02638 
02639 /* Sets up physical limits of plotting device. */
02640 
02641 void
02642 plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
02643 {
02644     if (xmin > xmax || ymin > ymax)
02645        plexit("plP_setphy: device minima must not exceed maxima");
02646 
02647     plsc->phyxmi = xmin;
02648     plsc->phyxma = xmax;
02649     plsc->phyymi = ymin;
02650     plsc->phyyma = ymax;
02651     plsc->phyxlen = xmax - xmin;
02652     plsc->phyylen = ymax - ymin;
02653 }
02654 
02655 /*--------------------------------------------------------------------------*\
02656  * void c_plscompression()
02657  *
02658  * Set compression. 
02659  * Has to be done before plinit.
02660 \*--------------------------------------------------------------------------*/
02661 
02662 void
02663 c_plscompression(PLINT compression)
02664 {
02665   if (plsc->level <= 0) 
02666      {
02667       plsc->dev_compression=compression;
02668      }
02669 }
02670 
02671 /*--------------------------------------------------------------------------*\
02672  * void c_plgcompression()
02673  *
02674  * Get compression
02675 \*--------------------------------------------------------------------------*/
02676 
02677 void
02678 c_plgcompression(PLINT *compression)
02679 {
02680     *compression = plsc->dev_compression;
02681 }
02682 
02683 
02684 /*--------------------------------------------------------------------------*\
02685  * void plP_getinitdriverlist()
02686  *
02687  * Check to see if a driver/stream has been initialised
02688  * Returns a space separated list of matches streams/drivers
02689  * If more than one stream uses the same device, then the device name
02690  * will be returned for each stream.
02691  * Caller must allocate enough memory for "names" to hold the answer.
02692 \*--------------------------------------------------------------------------*/
02693 
02694 void
02695 plP_getinitdriverlist(char *names)
02696 {
02697 int i;
02698 
02699 for (i=0;i<PL_NSTREAMS;++i)
02700    {
02701     if (pls[i]!=NULL)
02702        {
02703        if (i==0)
02704           strcpy(names,pls[i]->DevName);
02705        else
02706           { 
02707           strcat(names," ");
02708           strcat(names,pls[i]->DevName);
02709           }
02710        }
02711     else 
02712        break;
02713    }
02714 }
02715 
02716 
02717 /*--------------------------------------------------------------------------*\
02718  * PLINT plP_checkdriverinit()
02719  *
02720  * Checks from a list of given drivers which ones have been initialised
02721  * and returns the number of devices matching the list, or -1 if in error.
02722  * Effectively returns the number of streams matching the given stream.
02723 \*--------------------------------------------------------------------------*/
02724 
02725 PLINT plP_checkdriverinit( char *names)
02726 {
02727 char *buff;
02728 char *tok=NULL;
02729 PLINT ret=0;   /* set up return code to 0, the value if no devices match*/
02730 
02731 buff=(char *)malloc((size_t) PL_NSTREAMS*8); /* Allocate enough memory for 8 
02732                                                 characters for each possible stream */
02733 
02734 if (buff!=NULL)
02735    {
02736     memset(buff,0,PL_NSTREAMS*8);    /* Make sure we clear it               */
02737     plP_getinitdriverlist(buff);     /* Get the list of initialised devices */
02738 
02739     for (tok = strtok(buff, " ,");   /* Check each device against the "name" */
02740          tok; tok=strtok(0, " ,"))   /* supplied to the subroutine   */
02741         {
02742         if (strstr(names,tok)!=NULL)  /* Check to see if the device has been initialised */
02743            {
02744             ret++;                   /* Bump the return code if it has      */
02745            }                    
02746         }
02747     free(buff);                      /* Clear up that memory we allocated   */
02748     }
02749 else 
02750    ret=-1;                           /* Error flag */
02751 
02752 return(ret);
02753 }
02754 
02755 
02756 /*--------------------------------------------------------------------------*\
02757  * plP_image
02758  *
02759  * Author: Alessandro Mirone, Nov 2001
02760  * 
02761  * 
02762  * 
02763 \*--------------------------------------------------------------------------*/
02764 
02765 void
02766 plP_image(short *x, short *y, unsigned short *z , PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT dy, unsigned short zmin, unsigned short zmax)
02767 {
02768   PLINT i, npts;
02769   short *xscl, *yscl;
02770   int   plbuf_write;
02771 
02772   plsc->page_status = DRAWING;
02773 
02774   if (plsc->dev_fastimg == 0) {
02775     plimageslow(x, y, z, nx-1, ny-1, 
02776          xmin, ymin, dx, dy, zmin, zmax);
02777     return ;
02778   }
02779 
02780   if (plsc->plbuf_write) {
02781     IMG_DT img_dt;
02782 
02783     img_dt.xmin=xmin;
02784     img_dt.ymin=ymin;
02785     img_dt.dx=dx;
02786     img_dt.dy=dy;
02787 
02788     plsc->dev_ix = x;
02789     plsc->dev_iy = y;
02790     plsc->dev_z = z;
02791     plsc->dev_nptsX = nx;
02792     plsc->dev_nptsY = ny;
02793     plsc->dev_zmin = zmin;
02794     plsc->dev_zmax = zmax;
02795 
02796     plbuf_esc(plsc, PLESC_IMAGE, &img_dt);
02797   }
02798 
02799   /* avoid re-saving plot buffer while in plP_esc() */
02800   plbuf_write = plsc->plbuf_write;
02801   plsc->plbuf_write = 0; 
02802 
02803   npts = nx*ny;
02804   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) */
02805     PLINT clpxmi, clpxma, clpymi, clpyma;
02806     
02807     xscl = (short *) malloc(nx*ny*sizeof(short));
02808     yscl = (short *) malloc(nx*ny*sizeof(short));
02809     for (i = 0; i < npts; i++) {
02810       xscl[i] = x[i];
02811       yscl[i] = y[i];
02812     }
02813     sdifilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
02814     plsc->imclxmin = clpxmi;
02815     plsc->imclymin = clpymi;
02816     plsc->imclxmax = clpxma;
02817     plsc->imclymax = clpyma;
02818     grimage(xscl, yscl, z, nx, ny);    
02819     free(xscl);
02820     free(yscl);
02821   } else { 
02822     plsc->imclxmin = plsc->phyxmi;
02823     plsc->imclymin = plsc->phyymi;
02824     plsc->imclxmax = plsc->phyxma;
02825     plsc->imclymax = plsc->phyyma;
02826     grimage(x, y, z, nx, ny );
02827   }
02828   plsc->plbuf_write = plbuf_write;
02829 }