/* See figprocs.h */ /* Last edited on 2023-10-15 03:41:34 by stolfi */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* INTERNAL PROTOTYPES */ char *figprocs_graph_format_parms(WinData *w, GraphData *g); char *figprocs_approx_format_parms(WinData *w, GraphData *g, ApproxData *ga); char *figprocs_joint_range_format_parms(WinData *w, RangeData *jr); PSStream *figprocs_new_stream ( bool_t epsfmt, Interval xd, Interval yd, char *outName, char *gTag ); /* Opens a Postscript stream, for figures whose client plotting range is {xd} by {yd}. */ void figprocs_begin_plot ( PSStream *ps, Interval xpt, Interval ypt, char *figname, char *title, char *parmstr, char *subtitle ); /* Starts a new plot (non-EPS page or EPS figure) into the stream {ps}. The {figname} is used as the page name or as the figure name. */ void figprocs_draw_axes_and_tics ( PSStream *ps, PlotOptions *o, WinData *w, char *xticfmt, char *yticfmt ); /* Draws axes and tic marks. The axes span the client intervals {w->xpt} and {w->ypt}. Also plots {n+1} tic marks spanning the ranges {xtic} and {ytic}. Assumes that the scale is {w->scale} points per client unit. */ /* IMPLEMENTATIONS */ char *figprocs_graph_format_parms(WinData *w, GraphData *g) { char *s = (char *) malloc(300); sprintf(s, "%s\nx in [%f _ %f]\ny in [%f _ %f]\n%d intervals in [%f _ %f]", g->descr, w->xpt.lo, w->xpt.hi, w->ypt.lo, w->ypt.hi, g->nia, g->xia.lo, g->xia.hi ); return(s); } char *figprocs_approx_format_parms(WinData *w, GraphData *g, ApproxData *ga) { char *s = (char *) malloc(300); sprintf(s, "%s\nx in [%f _ %f]\ny in [%f _ %f]\ng^a(x) = %f*x + %f +/- %f", g->descr, w->xpt.lo, w->xpt.hi, w->ypt.lo, w->ypt.hi, ga->alpha, ga->gamma, ga->delta ); return(s); } char *figprocs_joint_range_format_parms(WinData *w, RangeData *jr) { char *s = (char *) malloc(5000); Interval xt = aa_range(jr->x); Interval yt = aa_range(jr->y); sprintf(s, "x in [%f _ %f]\ny in [%f _ %f]\nxt = [%f _ %f]\nyt = [%f _ %f]", w->xpt.lo, w->xpt.hi, w->ypt.lo, w->ypt.hi, xt.lo, xt.hi, yt.lo, yt.hi ); return(s); } PSStream *figprocs_new_stream ( bool_t epsfmt, Interval xd, Interval yd, char *outName, char *gTag ) { /* Compute the plot scale so that the largest dimension is 6 inches: */ Float wx = xd.hi - xd.lo; Float wy = yd.hi - yd.lo; Float wm = (wx > wy ? wx : wy); double scale = 6.0 * 72.0 / wm; /* Compute the canvas dimensions (excluding the margins): */ double hsize = scale*wx; /* Canvas H size. */ double vsize = scale*wy; /* Canvas V size. */ double mrg = 4.0; /* In pt. */ /* Create the Postscript stream: */ char *prefix = txtcat4(outName, "-fn-", gTag, "-"); PSStream *ps = pswr_new_stream(prefix, NULL, epsfmt, "doc", "letter", FALSE, hsize+2*mrg, vsize + 2*mrg); return ps; } void figprocs_begin_plot ( PSStream *ps, Interval xpt, Interval ypt, char *figname, char *title, char *parmstr, char *subtitle ) { pswr_new_canvas(ps, figname); pswr_new_picture(ps, xpt.lo, xpt.hi, ypt.lo, ypt.hi); if (! pswr_is_eps(ps)) { pswr_add_caption(ps, title, 0.0); pswr_add_caption(ps, parmstr, 0.0); pswr_add_caption(ps, subtitle, 0.0); } } void figprocs_draw_axes_and_tics ( PSStream *ps, PlotOptions *o, WinData *w, char *xticfmt, char *yticfmt ) { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); fltgraph_draw_axes(ps, w->xpt, w->ypt); Interval xtic = (Interval){-10.0,+10.0}; /* X interval for tics. */ Interval ytic = (Interval){-10.0,+10.0}; /* Y interval for tics. */ int ntic = 40; /* Number of tic intervals. */ /* Data for axis tics: */ Float tcsz = 1.5; /* Tic length (mm). */ Float mtc = 2.5/w->scale; /* Tic safety margin. */ Interval xtc = (Interval){w->xpt.lo + mtc, w->xpt.hi - mtc}; Interval ytc = (Interval){w->ypt.lo + mtc, w->ypt.hi - mtc}; pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); pswr_set_label_font(ps, "Times-Roman", o->fontSize); fltgraph_draw_tics(ps, 0, xtic.lo, xtic.hi, ntic, tcsz, xticfmt, 2.0, xtc); fltgraph_draw_tics(ps, 1, ytic.lo, ytic.hi, ntic, tcsz, yticfmt, 1.5, ytc); if (o->frame) { pswr_set_pen(ps, 0.0,0.0,0.0, 0.15, 0.0, 0.0); pswr_frame(ps); } } void figprocs_plot_ia_ar_aa_graphs(PlotOptions *o, WinData *w, GraphData *g, char *title) { PSStream *ps = figprocs_new_stream(o->eps, w->xpt, w->ypt, o->outName, g->tag); /* Pack the parameters as a string: */ char *parmstr = figprocs_graph_format_parms(w, g); /*** Ordinary interval arithmetic plot ***/ figprocs_begin_plot ( ps, w->xpt, w->ypt, "ia", title, parmstr, "Ordinary interval arithmetic" ); pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); iagraph_plot_boxes(ps, g->ia, g->xia, w->ypt, g->nia); if (o->color) { pswr_set_pen(ps, 0.0,0.0,0.5, 0.10, 0.0, 0.0); } else { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); } fltgraph_plot(ps, g->fp, g->xfp, w->ypt, g->nfp); figprocs_draw_axes_and_tics(ps, o, w, "%.1f", NULL); /*** Affine arithmetic plot ***/ figprocs_begin_plot ( ps, w->xpt, w->ypt, "aa", title, parmstr, "Affine arithmetic" ); pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); aagraph_plot_paralelograms(ps, g->aa, g->xia, w->ypt, g->nia); if (o->color) { pswr_set_pen(ps, 0.0,0.0,0.5, 0.10, 0.0, 0.0); } else { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); } fltgraph_plot(ps, g->fp, g->xfp, w->ypt, g->nfp); figprocs_draw_axes_and_tics(ps, o, w, "%.1f", NULL); /*** Affine arithmetic range plot ***/ figprocs_begin_plot ( ps, w->xpt, w->ypt, "ar", title, parmstr, "Affine arithmetic converted to intervals" ); pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); aagraph_plot_boxes(ps, g->aa, g->xia, w->ypt, g->nia); if (o->color) { pswr_set_pen(ps, 0.0,0.0,0.5, 0.10, 0.0, 0.0); } else { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); } fltgraph_plot(ps, g->fp, g->xfp, w->ypt, g->nfp); figprocs_draw_axes_and_tics(ps, o, w, "%.1f", NULL); pswr_close_stream(ps); } void figprocs_plot_approx(PlotOptions *o, WinData *w, GraphData *g, ApproxData *ga, char *title) { auto Float line_fp(Float x); Float line_fp(Float x) { return ga->alpha*x + ga->gamma; } AAP x, y; /* Plot interval for approximating line */ Float dx = 0.1*(ga->xap.hi - ga->xap.lo); Interval xln = (Interval){ga->xap.lo - dx, ga->xap.hi + dx}; MemP frame; char *tag = txtcat4("ap-", g->tag, "-", ga->tag); PSStream *ps = figprocs_new_stream(o->eps, w->xpt, w->ypt, o->outName, tag); /* Pack the parameters into a string: */ char *parmstr = figprocs_approx_format_parms(w, g, ga); figprocs_begin_plot ( ps, w->xpt, w->ypt, "aa", title, parmstr, "Approximation by affine form" ); aa_init(); frame = aa_top(); /* Construct the parallelogram: */ x = aa_from_interval(ga->xap); y = aa_affine(x, ga->alpha, One, ga->gamma, ga->delta); /* Draw/fill the parallelogram: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); aagraph_fill_and_draw_2d_range(ps, x, y, 0.75,0.75,0.75); /* Plot the graph of function {f}: */ if (o->color) { pswr_set_pen(ps, 0.0,0.0,0.5, 0.10, 0.0, 0.0); } else { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 0.0, 0.0); } fltgraph_plot(ps, g->fp, g->xfp, w->ypt, g->nfp); /* Plot the graph of the approximating line: */ if (o->color) { pswr_set_pen(ps, 0.0,0.5,0.0, 0.10, 0.0, 0.0); } else { pswr_set_pen(ps, 0.0,0.0,0.0, 0.10, 2.0, 1.0); } fltgraph_plot(ps, line_fp, xln, w->ypt, 1); /* Draw dotted lines at X range endpoints: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.07, 0.5, 1.5); Float ylo = ga->alpha*ga->xap.lo + ga->gamma - ga->delta; Float yhi = ga->alpha*ga->xap.hi + ga->gamma - ga->delta; pswr_segment(ps, ga->xap.lo, 0.0, ga->xap.lo, ylo); pswr_segment(ps, ga->xap.hi, 0.0, ga->xap.hi, yhi); /* Draw axes and tics: */ figprocs_draw_axes_and_tics(ps, o, w, NULL, NULL); /* Draw tics at X range endpoints: */ Float tcsz = 1.5; /* Tic length (mm). */ Float mtc = 2.5/w->scale; /* Tic safety margin. */ Interval xtc = (Interval){w->xpt.lo + mtc, w->xpt.hi - mtc}; fltgraph_draw_tics(ps, 0, ga->xap.lo, ga->xap.hi, 1, tcsz, "%.2f", 2.0, xtc); aa_flush(frame); pswr_close_stream(ps); } void figprocs_plot_joint_range(PlotOptions *o, WinData *w, RangeData *jr, char *title) { char *tag = "jr"; PSStream *ps = figprocs_new_stream(o->eps, w->xpt, w->ypt, o->outName, tag); char *parmstr = figprocs_joint_range_format_parms(w, jr); MemP frame; Interval xt, yt; /* Interval ranges of {x} and {y}. */ AAP xta, yta; /* Ditto, re-converted to affine forms. */ figprocs_begin_plot ( ps, w->xpt, w->ypt, "aa", title, parmstr, "Joint range of affine forms" ); aa_init(); frame = aa_top(); /* Compute X and Y ranges as intervals: */ xt = aa_range(jr->x); yt = aa_range(jr->y); /* Convert ranges back to affine forms: */ xta = aa_from_interval(xt); yta = aa_from_interval(yt); /* Draw/fill rectangle in light grey: */ pswr_set_pen(ps, 0.5,0.0,0.0, 0.10, 0.0, 0.0); aagraph_fill_and_draw_2d_range(ps, xta, yta, 0.90,0.90,0.90); /* Draw/fill joint range in darker grey: */ pswr_set_pen(ps, 0.5,0.0,0.0, 0.15, 0.0, 0.0); aagraph_fill_and_draw_2d_range(ps, jr->x, jr->y, 0.75,0.75,0.75); /* Draw dotted lines from box to tics: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.07, 0.5, 1.5); pswr_segment(ps, xt.lo, 0.0, xt.lo, yt.lo); pswr_segment(ps, xt.hi, 0.0, xt.hi, yt.lo); pswr_segment(ps, 0.0, yt.lo, xt.lo, yt.lo); pswr_segment(ps, 0.0, yt.hi, xt.lo, yt.hi); /* Draw axes and tics: */ figprocs_draw_axes_and_tics(ps, o, w, NULL, NULL); /* Draw tics at range endpoints: */ Float tcsz = 1.5; /* Tic length (mm). */ Float mtc = 2.5/w->scale; /* Tic safety margin. */ Interval xtc = (Interval){w->xpt.lo + mtc, w->xpt.hi - mtc}; Interval ytc = (Interval){w->ypt.lo + mtc, w->ypt.hi - mtc}; fltgraph_draw_tics(ps, 0, xt.lo, xt.hi, 1, tcsz, "%.0f", 2.0, xtc); fltgraph_draw_tics(ps, 1, yt.lo, yt.hi, 1, tcsz, "%.0f", 1.5, ytc); aa_flush(frame); pswr_close_stream(ps); }