/* See {gmo_ps_plot.h}. */ /* Last edited on 2020-10-03 21:18:02 by jstolfi */ #include #include #include #include #include #include #include #include #include #include #include #include #include frgb_t gmo_get_flat_color(gmo_t *P, gmo_opto_ix_t io); /* Get the color of the surface element {P->opto[io]}, assuming uniform white lighting all around. */ frgb_t gmo_get_flat_color(gmo_t *P, gmo_opto_ix_t io) { auto frgb_t get_color(gmo_opto_ix_t jo, frgb_t vis); /* The diffuse component of {P->opto[jo]}, multiplied by {vis}. */ return get_color(io, frgb_White); frgb_t get_color(gmo_opto_ix_t jo, frgb_t vis) { if (jo == -1) { return frgb_Black; } else if ((vis.c[0] < 0.001) && (vis.c[1] < 0.001) && (vis.c[2] < 0.001)) { return frgb_Black; } else { assert(jo < P->noptos); gmo_opto_t *o = &(P->opto[jo]); /* Compute fraction of underlayers that are visible: */ frgb_t under_vis = frgb_sub(&(frgb_White), &(o->color)); /* Get contribuition of underlayers: */ frgb_t under_color = get_color(o->next, under_vis); /* Add contribution of self: */ if(o->kind == gmo_opto_kind_ABSORB) { return under_color; } else { frgb_t self_color = frgb_mul(&(o->color), &vis); return frgb_add(&self_color, &under_color); } } } } void gmo_ps_plot(epswr_figure_t *epsf, gmo_t *P) { gmo_opto_ix_t cur_draw_opto = -1; /* Current opto for segment drawing. */ gmo_opto_ix_t cur_fill_opto = -1; /* Current opto for triangle filling. */ auto void set_color(gmo_knot_ix_t ik[], int nkn, bool_t fill); /* If {fill==TRUE}, sets the color for area filling of an element with knots {ik[0..nkn-1]}. If the optos of the knots are non-null and different from {cur_fill_opto}, calls {epswr_set_fill_color} with their average color, and updates {cur_fill_opto}. If {fill==FALSE}, does the same thing for the current draw color, using {cur_draw_opto} and {epswr_set_pen}. */ /* Get knot colors: */ frgb_t knot_color[P->nknots]; /* Final color of each knot (diffuse component). */ int ik; for (ik =0; ik < P->nknots; ik++) { gmo_knot_t *kn = &(P->knot[ik]); knot_color[ik] = gmo_get_flat_color(P, kn->opto); } /* Get points: */ r3_t point_pos[P->npoints]; /* Cartesian coordinates of each point. */ int ip; for (ip =0; ip < P->npoints; ip++) { point_pos[ip] = r3_from_hr3(&(P->point[ip])); } auto r3_t *get_knot_pos(gmo_knot_ix_t ik); /* Returns the Cartesian coordinates of the knot {ik}, taken from {point_pos}. */ /* Plot items in three passes: tris, slugs, dots. */ int pass; for (pass = 2; pass >= 0; pass--) { auto bool_t plot_dot(gmo_item_ix_t ix, gmo_item_dot_t *t); auto bool_t plot_slug(gmo_item_ix_t ix, gmo_item_slug_t *t); auto bool_t plot_tri(gmo_item_ix_t ix, gmo_item_tri_t *t); if ((pass == 1) || (pass == 2)) { /* Set a default pen (thin, black, solid), just in case: */ epswr_set_pen(epsf, 0,0,0, 0.1, 0,0); } gmo_item_ix_t res = gmo_enum_items(P, plot_dot, plot_slug, plot_tri); assert(res == -1); bool_t plot_dot(gmo_item_ix_t ix, gmo_item_dot_t *t) { return FALSE; if (pass == 0) { /* Should use the radius information. */ r3_t *p = get_knot_pos(t->kn); set_color(&(t->kn), 1, TRUE); epswr_dot(epsf, p->c[0], p->c[1], 0.2, TRUE, TRUE); } } bool_t plot_slug(gmo_item_ix_t ix, gmo_item_slug_t *t) { if (pass == 1) { /* Should use the radius information. */ r3_t *p = get_knot_pos(t->kn[0]); r3_t *q = get_knot_pos(t->kn[1]); set_color(t->kn, 2, FALSE); epswr_segment(epsf, p->c[0], p->c[1], q->c[0], q->c[1]); } return FALSE; } bool_t plot_tri(gmo_item_ix_t ix, gmo_item_tri_t *t) { if (pass == 2) { r3_t *p = get_knot_pos(t->kn[0]); r3_t *q = get_knot_pos(t->kn[1]); r3_t *r = get_knot_pos(t->kn[2]); set_color(t->kn, 3, TRUE); epswr_triangle ( epsf, p->c[0], p->c[1], q->c[0], q->c[1], r->c[0], r->c[1], TRUE, FALSE ); } return FALSE; } } r3_t *get_knot_pos(gmo_knot_ix_t ik) { assert((ik >= 0) && (ik < P->nknots)); gmo_knot_t *kn = &(P->knot[ik]); gmo_point_ix_t ip = kn->pt; assert((ip >= 0) && (ip < P->npoints)); return &(point_pos[ip]); } void set_color(gmo_knot_ix_t ik[], int nkn, bool_t fill) { /* Gather optos of end-knots: */ int i; gmo_opto_ix_t io[nkn]; /* Index {io[i]} is the opto index of knot {ik[i]}. */ for (i = 0; i < nkn; i++) { gmo_knot_ix_t iki = ik[i]; assert((iki >= 0) && (iki < P->nknots)); io[i] = P->knot[iki].opto; assert((io[i] >= -1) && (io[i] < P->noptos)); } /* Get current opto: */ gmo_opto_ix_t cur_opto = (fill? cur_fill_opto : cur_draw_opto); /* Collect non-null optos, save last one {new_opto}, check if all equal: */ int nop = 0; gmo_opto_ix_t new_opto = -1; bool_t same = TRUE; for (i = 0; i < nkn; i++) { if (io[i] != -1) { if ((new_opto != -1) && (new_opto != io[i])) { same = FALSE; } new_opto = io[i]; nop++; } } /* If there are no optos, keep current color: */ if (nop == 0) { return; } /* Average colors; */ frgb_t color; if (same) { /* All knots with non-null opto have same opto {new_opto}: */ assert(new_opto > 0); if (new_opto == cur_opto) { /* Already set: */ return; } color = gmo_get_flat_color(P, new_opto); } else { /* Knots have different optos, mix their colors: */ color = frgb_Black; for (i = 0; i < nkn; i++) { if (io[i] != -1) { frgb_t ci = gmo_get_flat_color(P, io[i]); color = frgb_mix(1.0, &color, 1.0/nop, &ci); } } new_opto = -1; /* No use remebering it. */ } if (fill) { epswr_set_fill_color(epsf, color.c[0], color.c[1], color.c[2]); cur_fill_opto = new_opto; } else { epswr_set_pen(epsf, color.c[0], color.c[1], color.c[2], 0.1, 0,0); cur_draw_opto = new_opto; } } }