/* See plot1d_mscale.h. */ /* Last edited on 2012-12-11 23:22:09 by stolfilocal */ #include #include #include #include #include #include #include #include #include #define DIM 1 #define MAXTAGSZ 200 #define DRAW_COORD_LINES FALSE #define DRAW_FRAME FALSE void plot_1d_logY_graph_decoration ( PSStream *ps, plot_options_t *o, interval_t fr[], /* Function domain and range, for ticks &c. */ double tstep[], /* Space between major (labeled) ticks. */ double sstep[], /* Space between minor (unlabeled) ticks. */ interval_t gr[], /* Function domain and range for graph/clip. */ double mag[], /* Function scales (one function unit in client units). */ interval_t win[], /* Plotting area (client units). */ double scale /* Plot scale (one client unit in mm). */ ) { double ht = (o->eps ? 0.5 : 1.0)/scale; /* Half-length of major ticks. */ double hs = 0.5*ht; /* Half-length of minor ticks. */ /* Draw coordlines and tick marks: */ /* Minor ticks */ plot_1d_ticks_and_lines ( ps, o, 0, hs, sstep[0], FALSE, FALSE, &(fr[0]), mag[0], &(gr[1]), mag[1], win ); plot_1d_ticks_and_lines ( ps, o, 1, hs, sstep[1], FALSE, FALSE, &(fr[1]), mag[1], &(gr[0]), mag[0], win ); /* Major ticks */ plot_1d_ticks_and_lines ( ps, o, 0, ht, tstep[0], TRUE, FALSE, &(fr[0]), mag[0], &(gr[1]), mag[1], win ); plot_1d_ticks_and_lines ( ps, o, 1, ht, tstep[1], TRUE, FALSE, &(fr[1]), mag[1], &(gr[0]), mag[0], win ); /* Draw coordinate axes: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); plot_1d_axes(ps, o, &(gr[0]), mag[0], &(gr[1]), mag[1]); if (DRAW_FRAME) { /* Draw frame around plot: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.15, 0.0, 0.0); pswr_frame(ps); } } void plot_1d_function ( PSStream *ps, plot_options_t *o, double func (double x), double xstep, interval_t xr, double xmag, interval_t yr, double ymag ) { double x1 = NAN; /* Previous sample point */ double y1; /* Function value at {x1}. */ auto void plot_sample(double x); void plot_sample(double x) { double x0 = x; double y0 = func(x0); if ( (!isnan(x1)) && ((y0 >= LO(yr)) || (y0 <= HI(yr))) && ((y1 >= LO(yr)) || (y1 <= HI(yr))) ) { pswr_segment(ps, xmag*x1, ymag*y1, xmag*x0, ymag*y0); } x1 = x0; y1 = y0; } int N = (int)(1.0/xstep); int Nmin = (int)ceil(LO(xr)*N); int Nmax = (int)floor(HI(xr)*N); double h = 0.00001*(HI(xr) - LO(xr)); int i; fprintf(stderr, "xr = [%7.4f _ %7.4f] xstep = %7.4f i = {%d..%d}\n", LO(xr), HI(xr), xstep, Nmin, Nmax); for (i = Nmin; i <= Nmax; i++) { double x = ((double) i)*xstep; if ((i % N) == 0) { plot_sample(x-h); plot_sample(x+h); } else { plot_sample(x); } } fflush(ps->file); } void plot_1d_axes ( PSStream *ps, plot_options_t *o, interval_t *xr, double xmag, interval_t *yr, double ymag ) { if ((LO(*xr) < 0.0) && (HI(*xr) > 0.0)) { double tlo = ymag*LO(*yr); double thi = ymag*HI(*yr); pswr_segment(ps, 0.0, tlo, 0.0, thi); } if ((LO(*yr) < 0.0) && (HI(*yr) > 0.0)) { double tlo = xmag*LO(*xr); double thi = xmag*HI(*xr); pswr_segment(ps, tlo, 0.0, thi, 0.0); } } void plot_1d_coord_lines ( PSStream *ps, plot_options_t *o, plot_1d_axis_t ax, /* Axis PERPENDICULAR to the lines. */ int nsteps, /* Number of steps (num of lines minus 1) */ interval_t *nr, /* Cordinate range along axis {ax} */ double nmag, /* Extra scale factor along axis {ax}. */ interval_t *tr, /* Range along the lines. */ double tmag /* Extra scale factor along the lines. */ ) { /* Plot coord lines: */ int i; double tlo = tmag*LO(*tr); double thi = tmag*HI(*tr); for (i = 0; i <= nsteps; i++) { double t = (nsteps == 0 ? 0.5 : ((double)i)/nsteps); double s = (nsteps == 0 ? 0.5 : ((double)(nsteps-i))/nsteps); double c = s*LO(*nr) + t*HI(*nr); double cp = nmag*c; /* Client coordinate for plotting */ if (ax == 0) { pswr_segment(ps, cp, tlo, cp, thi); } else { pswr_segment(ps, tlo, cp, thi, cp); } } } void plot_1d_ticks_and_lines ( PSStream *ps, plot_options_t *o, plot_1d_axis_t ax, /* Axis along which ticks are to be placed. */ double hsize, /* Half-length of tick marks (client units). */ double step, /* Spacing between ticks (func units). */ bool_t labeled, /* TRUE to print label at left/under each tick. */ bool_t lines, /* TRUE draws coord lines at tick positions. */ interval_t *cr, /* Only place ticks within this coordinate range. */ double cmag, /* Extra scale factor along axis {ax}. */ interval_t *gr, /* Trim coord lines to this coordinate range. */ double gmag, /* Extra scale factor across axis {ax}. */ interval_t win[] /* Plot window in client units. */ ) { double wd = HI(*cr) - LO(*cr); int nt; /* Number of tick intervals. */ nt = (floor)(wd/step + 0.5); char *fmt; /* Format for major tick labels in each axis. */ if (labeled) { /* Use sign if negative; use fraction if small step. */ fmt = plot_1d_tick_format(wd/((double)(nt)), cr); } else { fmt = NULL; } if (lines) { /* Draw coord lines: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.075, 0.50, 0.50); plot_1d_coord_lines(ps, o, ax, nt, cr, cmag, gr, gmag); } pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); pswr_set_label_font(ps, "TimesRoman", (o->eps ? 8.0 : 12.0)); plot_1d_ticks(ps, o, ax, hsize, fmt, nt, cr, cmag, win); } char *plot_1d_tick_format(double step, interval_t *fr) { /* If the range extends into negative numbers, print the sign too: */ bool_t wsign = (LO(*fr) < -0.9999*step); /* Compute the number {nd} of decimals needed: */ int nd = 0; while ((nd <= 2) && (fabs(floor(step + 0.5) - step) > 1.0e-5 * step)) { step *= 10.0; nd++; } /* If the range extends into negative numbers, print the sign too: */ if (wsign) { return (nd == 0 ? "%+.0f" : (nd == 1 ? "%+.1f" : "%+.2f")); } else { return (nd == 0 ? "%.0f" : (nd == 1 ? "%.1f" : "%.2f")); } } void plot_1d_ticks ( PSStream *ps, plot_options_t *o, plot_1d_axis_t ax, /* Axis along which ticks are to be placed. */ double hsize, /* Half-length of tick marks (client units). */ char *fmt, /* Format for tick labels, or NULL, */ int nsteps, /* Number of tick steps in {cr}. */ interval_t *cr, /* Only place ticks within this coordinate range. */ double mag, /* Scale fator from func units to client units. */ interval_t win[] /* Plot window in client units. */ ) { int i; double tickmrg = 2.5*hsize; char buf[300]; /* ?? Should check whether 0 is well inside range {win[1-ax]}. */ /* ?? However that requires knowing the character's bbox. */ for (i = 0; i <= nsteps; i++) { double t = (nsteps == 0 ? 0.5 : ((double)i)/nsteps); double s = (nsteps == 0 ? 0.5 : ((double)(nsteps-i))/nsteps); double c = s*LO(*cr) + t*HI(*cr); double cp = mag*c; /* Client coordinate for plotting */ if ( (cp > LO(win[ax]) + tickmrg) && (cp <= HI(win[ax]) - tickmrg) && (mag*fabs(c) > tickmrg) ) { if (fmt != NULL) { sprintf(buf, fmt, c); } if (ax == 0) { pswr_segment(ps, cp, -hsize, cp, +hsize); if (fmt != NULL) { pswr_label(ps, buf, cp, -hsize, 0.5, 1.3); } } else if (ax == 1) { pswr_segment(ps, -hsize, cp, +hsize, cp); if (fmt != NULL) { pswr_label(ps, buf, -hsize, cp, 1.3, 0.5); } } else { affirm(FALSE, "bad axis"); } } } fflush(ps->file); }