/* See hxg_ps.h */ /* Last edited on 2012-12-08 23:34:58 by stolfilocal */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include void hxg_ps_fill_polygon(PSStream *ps, r2_vec_t *p) { int np = p->ne; double x[np+2], y[np+2]; /* For filling, we copy all vertices from {p} into {x,y}, inserting the origin (0,0) between every two loops, as well as before the first loop and after the last loop. This should give the right effect with even/odd filling rule. */ x[0] = 0; y[0] = 0; int ip; for (ip = 0; ip < np; ip++) { r2_t *pi = &(p->e[ip]); if (r2_is_finite(pi)) { x[ip+1] = X(*pi); y[ip+1] = Y(*pi); } else { x[ip+1] = 0; y[ip+1] = 0; } } x[np+1] = 0; y[np+1] = 0; pswr_polygon(ps, TRUE, x, y, np+2, TRUE, FALSE, TRUE); } void hxg_ps_plot_rect_stroke ( PSStream *ps, /* Where to plot. */ r2_t *a, /* Start of stroke. */ r2_t *b, /* End of stroke. */ double r, /* Half-width of stroke. */ bool_t fill, bool_t draw /* Plotting options. */ ) { /* Zero-area figures contain no pixels: */ if (r == 0) { return; } /* Get the displacement vector from {a} to {b}: */ r2_t d; r2_sub(b, a, &d); /* Zero-area figures contain no pixels: */ if ((X(d) == 0) && (Y(d) == 0)) { return; } /* Get its direction: */ r2_dir(&d, &d); /* Get a vector {v} with length {r} perpendicular to {d}: */ r2_t v = (r2_t){{-r*Y(d), r*X(d)}}; /* Build the polygon: */ double x[5], y[5]; r2_t p; r2_add(a, &v, &p); x[0] = X(p); y[0] = Y(p); r2_add(b, &v, &p); x[1] = X(p); y[1] = Y(p); r2_sub(b, &v, &p); x[2] = X(p); y[2] = Y(p); r2_sub(a, &v, &p); x[3] = X(p); y[3] = Y(p); /* Close it: */ x[4] = x[0]; y[4] = y[0]; /* Plot the polygon: */ pswr_polygon(ps, TRUE, x, y, 5, fill, draw, FALSE); } void hxg_ps_plot_circle ( PSStream *ps, /* Where to plot. */ r2_t *c, /* Center of circle. */ double r, /* Radius of circle. */ bool_t fill, bool_t draw /* Plotting options. */ ) { /* This one is easy: */ pswr_circle(ps, X(*c), Y(*c), r, fill, draw); } void hxg_ps_plot_dot ( PSStream *ps, /* Where to plot. */ r2_t *c, /* Center of circle. */ double r, /* Radius of circle (mm). */ bool_t fill, bool_t draw /* Plotting options. */ ) { /* This one is easy too: */ pswr_dot(ps, X(*c), Y(*c), r, fill, draw); } void hxg_ps_draw_polyline(PSStream *ps, r2_vec_t *p) { int np = p->ne; /* We must stroke the segments separately. */ /* We trust that joints are rounded. */ int ip; double xa = INF, ya = INF; for (ip = 0; ip < np; ip++) { r2_t *pb = &(p->e[ip]); if (r2_is_finite(pb)) { double xb = X(*pb); double yb = Y(*pb); if (xa == INF) { /* Start each polyline with an infinitesimal stroke, so that if it has only one vertex, it will still plot as a dot. (Would a zero-length stroke work too?) */ xa = xb - 1.0e-6; ya = yb - 1.0e-6; } pswr_segment(ps, xa, ya, xb, yb); xa = xb; ya = yb; } else { xa = INF; ya = INF; } } } PSStream *hxg_ps_init_plot ( interval_t B[], char *name, bool_t eps, char *paperSize ) { /* Compute the plotting ranges with some slop: */ double zxraw = HI(B[0]) - LO(B[0]), zyraw = HI(B[1]) - LO(B[1]); /* Extents. */ double mx = 0.05 * zxraw, my = 0.05 * zyraw; /* Margins */ double xmin = LO(B[0]) - mx, xmax = HI(B[0]) + mx, zx = xmax - xmin; double ymin = LO(B[1]) - my, ymax = HI(B[1]) + my, zy = ymax - ymin; /* Choose/get nominal page/figure size and margins: */ double hPaper, vPaper; double hMargin, vMargin; if (eps) { /* Set figure width to 6 inches, height in proportion, plus 4pt margin: */ hMargin = 4.0; vMargin = 4.0; hPaper = 6.0*72.0 + 2*hMargin; vPaper = hPaper * zy/zx + 2*vMargin; } else { /* Set figure width and height to paper size, and margins to 1 inch: */ pswr_get_paper_dimensions(paperSize, FALSE, &hPaper, &vPaper); hMargin = 72.0; vMargin = 72.0; } /* Create a new Postscript document, with canvas size larger : */ PSStream *ps = pswr_new_stream(name, NULL, eps, "doc", paperSize, FALSE, hPaper, vPaper); /* Set one picture per page, with the right format: */ int capLines = (eps ? 0 : 4); pswr_set_canvas_layout(ps, zx, zy, TRUE, hMargin, vMargin, capLines, 1,1); /* First picture: */ pswr_new_picture (ps, xmin, xmax, ymin, ymax); return ps; } void hxg_ps_plot_pixels ( PSStream *ps, /* Where to plot. */ hxg_canvas_t *cvs, /* The canvas to plot. */ double pixv[], /* Pixel values, stored in the standard way. */ int maxv, /* Max pixel value in tables. */ double *r, /* Radius table. */ hxg_color_t *fill_c, /* Fill color table. */ hxg_color_t *draw_c /* Draw color table. */ ) { /* Get hold of params: */ int nx = X(cvs->size); /* Num of points per canvas row. */ int ny = Y(cvs->size); /* Num of rows in canvas. */ /* Current pixel value, initial state not relevant: */ double cv = 0; /* Current dot radius: */ double cr = INF; /* Current Postscript state, starts undefined: */ hxg_color_t cf = (hxg_color_t){NAN,NAN,NAN}; /* Current fill color. */ hxg_color_t cd = (hxg_color_t){NAN,NAN,NAN}; /* Current draw color. */ /* Plot pixels: */ int ix, iy, k; for (iy = 0; iy < ny; iy++) { for (ix = 0,k = iy*nx; ix < nx; ix++,k++) { double val = pixv[k]; if ((cr == INF) || (val != cv)) { /* Adjust pixel value for lookup: */ if ((val < -maxv) || (val > maxv)) { val = maxv; } else if (val < 0) { val = -val; } int iv = (int)floor(val + 0.5); /* Get radius: */ cr = r[iv]; if (cr > 0) { cf = fill_c[iv]; cd = draw_c[iv]; if (val < 0) { /* Complement {cf}: */ if (cf.R < 0) { cf = (hxg_color_t){0,0,0}; } else { cf = (hxg_color_t){1-cf.R,1-cf.G,1-cf.B}; } } pswr_set_pen(ps, cd.R, cd.G, cd.B, 0.1, 0.0, 0.0); pswr_set_fill_color(ps, cf.R, cf.G, cf.B); } cv = val; } if (cr > 0) { r2_t c = hxg_pixel_pos(cvs, (i2_t){{ix,iy}}); pswr_dot(ps, X(c), Y(c), cr, TRUE, TRUE); } } } } void hxg_ps_fill_circles ( PSStream *ps, /* Where to plot. */ r2_vec_t *c, /* Centers of circles. */ double_vec_t *h, /* Variable radius. */ double r /* Fixed radius. */ ) { int i; for (i = 0; i < c->ne; i++) { r2_t *ci = &(c->e[i]); double hi = ((h == NULL) || (i > h->ne) ? 0 : h->e[i]); pswr_circle(ps, X(*ci), Y(*ci), hi+r, TRUE, FALSE); } } void hxg_ps_fill_dots ( PSStream *ps, /* Where to plot. */ r2_vec_t *c, /* Centers of circles. */ double r /* Dot radius (mm). */ ) { int i; for (i = 0; i < c->ne; i++) { r2_t *ci = &(c->e[i]); pswr_dot(ps, X(*ci), Y(*ci), r, TRUE, FALSE); } } void hxg_ps_show_labels ( PSStream *ps, /* Where to plot. */ r2_vec_t *c, /* Reference points. */ r2_t disp, /* Extra displacement for all ref pts. */ double xalign, /* Horiz rel pos of label to align with ref X. */ double yalign, /* Vert rel pos of label to align with ref Y. */ double ptsize /* Text point size. */ ) { int i; pswr_set_label_font(ps, "Courier", ptsize); for (i = 0; i < c->ne; i++) { r2_t *ci = &(c->e[i]); r2_t p; r2_add(ci, &disp, &p); char *txt = NULL; asprintf(&txt, "%d", i); pswr_label(ps, txt, X(p), Y(p), 0.0, xalign, yalign); free(txt); } } void hxg_ps_draw_circles ( PSStream *ps, /* Where to plot. */ r2_vec_t *c, /* Centers of circles. */ double_vec_t *h, /* Variable radius. */ double r /* Fixed radius. */ ) { int i; for (i = 0; i < c->ne; i++) { r2_t *ci = &(c->e[i]); double hi = ((h == NULL) || (i > h->ne) ? 0 : h->e[i]); pswr_circle(ps, X(*ci), Y(*ci), hi+r, FALSE, TRUE); } } void hxg_ps_fill_sausage ( PSStream *ps, /* Where to plot. */ r2_vec_t *p, /* Vertices of sausage. */ double r /* Half-width of sausage. */ ) { int np = p->ne; int ip; r2_t *pa = NULL; for (ip = 0; ip < np; ip++) { r2_t *pb = &(p->e[ip]); if (r2_is_finite(pb)) { if (pa != NULL) { hxg_ps_plot_rect_stroke(ps, pa, pb, r, TRUE, FALSE); } hxg_ps_plot_circle(ps, pb, r, TRUE, FALSE); pa = pb; } else { pa = NULL; } } }