/* See {hedge_draw.h}. */ /* Copyright (C) 2023 Jorge Stolfi, UNICAMP */ /* Last edited on 2025-05-07 17:24:38 by stolfi */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define debug FALSE #define hedge_draw_arc_record_TIME 0.35 /* Relative position of arc box along arc. */ /* Detail dimensions (all to be multiplied by a given {dunit}): */ #define hedge_draw_vert_RAD 1.0 /* Radius of vertex dots in mesh view. */ #define hedge_draw_face_dot_RAD 3.0 /* Radius of face dot in mesh view. */ #define draw_edge_arc_arrow_WIDTH 5.0 #define draw_edge_arc_arrow_LENGTH 6.0 /* Dimensions of arc arrowhead on mesh view. */ #define hedge_draw_arc_record_HU 3.0 #define hedge_draw_arc_record_HV 2.5 /* Half-sides of an arc record box in data structure view. */ #define hedge_draw_vert_record_RAD 3.0 /* Radius of vertex record in data structure view. */ #define hedge_draw_face_record_RAD 3.0 /* Radius of face record in data structure view. */ #define hedge_draw_struct_link_arrow_WIDTH 0.8 #define hedge_draw_struct_link_arrow_LENGTH 2.5 /* Dimensions of link arrowhead on data structure view. */ #define hedge_draw_struct_link_dot_RAD 0.35 /* Radius of link tail dot on data structure view. */ void hedge_draw_get_edge_bezier_points(hedge_arc_t *a, r2_t *p0, r2_t *p1, r2_t *p2, r2_t *p3); /* Returns the Bézier control points {p0,p1,p2,p3} for the edge of the arc {a}. The endpoints {p0} and {p1} will be {a.org.pos} and {a.dst.pos}. The other two points are computed based on the endpoints and the bending parameter {a.bend}. */ void hedge_draw_get_arc_point(hedge_arc_t *a, double t, r2_t *p, r2_t *pu, r2_t *pv); /* Returns the point {*p} that is on the edge of arc {a}, {t} of the way from {a.org} to {a.dst}. If {pv} is not {NULL}, stores the unit tangent direction vector in {*pu}, and, {pv} is not {NULL}, stores into it the unit normal direction pointing to the left. */ r2_t hedge_draw_get_arc_record_point(r2_t *p, r2_t *pu, r2_t *pv, double u, double v, double dunit); /* Returns the absolute {(x,y)} coordinates of the point of an arc record box that has coordinates {(u,v)} in the box coordinate system, which has origin {p} orthonormal axis direction vectors {pu} and {pv}, and whose units are the box half-sizes in those directions. Thus {u=+1.0,v=-1.0} is the {+u,-v} corner of the box. */ r2_t hedge_draw_get_vert_record_point(r2_t *p, r2_t *q, double dunit); /* Returns a point where the line from {p} to {q} crosses the edge of the box that represents the vertex record with center {q}. */ r2_t hedge_draw_get_face_record_point(r2_t *p, r2_t *q, double dunit); /* Returns a point where the line from {p} to {q} crosses the edge of the box that represents the face record with center {q}. */ /* DRAW MESH VIEW */ void hedge_draw_edge(epswr_figure_t *eps, hedge_arc_t *a, double ghdash) { hedge_arc_t *b = a->twin; hedge_vert_t *org = a->org; hedge_vert_t *dst = b->org; if (debug) { fprintf(stderr, " a = ( %u --> %u)\n", org->id, dst->id); } if ((! org->show) && (! dst->show)) { return; } r2_t p0, p1, p2, p3; hedge_draw_get_edge_bezier_points(a, &p0, &p1, &p2, &p3); if ((! org->show) || (! dst->show)) { r2_t p01, p12, p23, p012, p123, p0123; r2_bezier_split ( 0, 1, &p0, &p1, &p2, &p3, 0.5, &p01, &p12, &p23, &p012, &p123, &p0123, NULL ); if (! dst->show) { p1 = p01; p2 = p012; p3 = p0123;} else if (! org->show) { p0 = p0123; p1 = p123; p2 = p23; } else { assert(FALSE); } } bool_t is_ghost = (a->left == b->left); if (is_ghost && (ghdash > 0)) { /* Ghost edges, if drawn, are dashed: */ epswr_set_pen_dashing(eps, ghdash, 0.75*ghdash); } else { /* Normal edge, solid: */ epswr_set_pen_dashing(eps, 0, 0); } if ((ghdash >= 0) | (! is_ghost)) { epswr_curve ( eps, p0.c[0], p0.c[1], p1.c[0], p1.c[1], p2.c[0], p2.c[1], p3.c[0], p3.c[1] ); } } void hedge_draw_arc_arrowhead(epswr_figure_t *eps, hedge_arc_t *a, double tim, double dunit) { r2_t p, pu; hedge_draw_get_arc_point(a, tim, &p, &pu, NULL); if (debug) { r3_t *org = &(a->org->pos); r3_t *dst = &(a->twin->org->pos); r3_gen_print(stderr, org, "%.2f", " org = ( ", " ", " )"); r3_gen_print(stderr, dst, "%.2f", " dst = ( ", " ", " )"); r2_gen_print(stderr, &p, "%.2f", " p = ( ", " ", " )"); r2_gen_print(stderr, &pu, "%.2f", " pu = ( ", " ", " )\n"); } double width = dunit*draw_edge_arc_arrow_WIDTH; double length = dunit*draw_edge_arc_arrow_LENGTH; r2_t q; r2_mix(1.0, &p, 2.0, &pu, &q); epswr_set_pen_dashing(eps, 0,0); epswr_arrowhead(eps, p.c[0], p.c[1], q.c[0], q.c[1], width/2, 0.0, length, 1.0, TRUE, TRUE); } void hedge_draw_vert(epswr_figure_t *eps, hedge_vert_t *v, double dunit) { double rad = dunit*hedge_draw_vert_RAD; if ((v->show) && (rad > 0)) { epswr_set_pen_dashing(eps, 0,0); epswr_dot(eps, v->pos.c[0], v->pos.c[1], rad, TRUE, TRUE); } } void hedge_draw_face_dot(epswr_figure_t *eps, hedge_face_t *f, double dunit) { double rad = dunit*hedge_draw_face_dot_RAD; if ((f->show) && (rad > 0)) { epswr_set_pen_dashing(eps, 0,0); epswr_dot(eps, f->ctr.c[0], f->ctr.c[1], rad, TRUE, TRUE); } } void hedge_fill_face(epswr_figure_t *eps, hedge_face_t *f) { if (! f->show) { return; } hedge_arc_t *a0 = f->side; /* Compute degree of face: */ int32_t deg = 0; hedge_arc_t *ai = a0; do { deg++; ai = ai->next; } while (ai != a0); fprintf(stderr, " degree of face 0 = %d\n", deg); /* Create array of vertex positions: */ double vx[deg], vy[deg]; int32_t iv = 0; ai = a0; do { r3_t *vp = &(ai->org->pos); vx[iv] = vp->c[0]; vy[iv] = vp->c[1]; iv++; ai = ai->next; } while (ai != a0); bool_t evenOdd = TRUE; epswr_polygon(eps, TRUE, vx, vy, deg, TRUE, FALSE, evenOdd); } void hedge_draw_get_edge_bezier_points(hedge_arc_t *a, r2_t *p0, r2_t *p1, r2_t *p2, r2_t *p3) { hedge_arc_t *b = a->twin; hedge_vert_t *org = a->org; hedge_vert_t *dst = b->org; (*p0) = (r2_t){{ org->pos.c[0], org->pos.c[1] }}; (*p3) = (r2_t){{ dst->pos.c[0], dst->pos.c[1] }}; double ebend = (a->bend - b->bend)/2; r2_bezier_from_bend(p0, p3, ebend, p1, p2); } void hedge_draw_get_arc_point(hedge_arc_t *a, double t, r2_t *p, r2_t *pu, r2_t *pv) { r2_t p0, p1, p2, p3; hedge_draw_get_edge_bezier_points(a, &p0, &p1, &p2, &p3); r2_bezier_eval(0, 1, &p0, &p1, &p2, &p3, t, p, pu); (void)r2_dir(pu, pu); if ((pu != NULL) && (pv != NULL)) { (*pv) = (r2_t){{ -pu->c[1], +pu->c[0] }}; } } /* DATA STRUCTURE VIEW */ void hedge_draw_arc_record(epswr_figure_t *eps, hedge_arc_t *a, double dunit) { if (a->org->show) { r2_t p, pu, pv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); double hu = dunit*hedge_draw_arc_record_HU; double hv = dunit*hedge_draw_arc_record_HV; r2_t qu, qv; r2_scale(hu, &pu, &qu); r2_scale(hv, &pv, &qv); epswr_set_pen_dashing(eps, 0,0); epswr_parallelogram ( eps, p.c[0], p.c[1], qu.c[0], qu.c[1], qv.c[0], qv.c[1], TRUE, TRUE ); } } void hedge_draw_vert_record(epswr_figure_t *eps, hedge_vert_t *v, double dunit) { double rad = dunit*hedge_draw_vert_record_RAD; if ((v->show) && (rad > 0)) { epswr_set_pen_dashing(eps, 0,0); epswr_dot(eps, v->pos.c[0], v->pos.c[1], rad, TRUE, TRUE); } } void hedge_draw_face_record(epswr_figure_t *eps, hedge_face_t *f, double dunit) { double rad = dunit*hedge_draw_face_record_RAD; if ((f->show) && (rad > 0)) { epswr_set_pen_dashing(eps, 0,0); epswr_dot(eps, f->ctr.c[0], f->ctr.c[1], rad, TRUE, TRUE); } } void hedge_draw_arc_next_link(epswr_figure_t *eps, hedge_arc_t *a, double dunit) { hedge_arc_t *b = a->next; if (a->org->show) { /* Link exits from top left quarter of {a}'s box: */ r2_t p, pu, pv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); r2_t pp = hedge_draw_get_arc_record_point(&p, &pu, &pv, +0.5, +0.5, dunit); /* Link goes to left side of {b}'s box, near bottom: */ r2_t q, qu, qv; hedge_draw_get_arc_point(b, tim, &q, &qu, &qv); r2_t qq = hedge_draw_get_arc_record_point(&q, &qu, &qv, -0.7, +1.0, dunit); double bend = -0.5; /* Cut in half if other end is invisible: */ if (! b->org->show) { r2_mix(0.5, &pp, 0.5, &qq, &qq); bend = bend/4; } hedge_draw_struct_link(eps, &pp, &qq, bend, dunit); } } void hedge_draw_arc_twin_link(epswr_figure_t *eps, hedge_arc_t *a, double dunit) { hedge_arc_t *b = a->twin; if (a->org->show) { /* Link exits from top right quarter of {a}'s box: */ r2_t p, pu, pv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); r2_t pp = hedge_draw_get_arc_record_point(&p, &pu, &pv, +0.5, -0.5, dunit); /* Link goes near bottom center of {b}'s box: */ r2_t q, qu, qv; hedge_draw_get_arc_point(b, tim, &q, &qu, &qv); r2_t qq = hedge_draw_get_arc_record_point(&q, &qu, &qv, +1.0, 00.0, dunit); double bend = -0.5; hedge_draw_struct_link(eps, &pp, &qq, bend, dunit); } } void hedge_draw_arc_org_link(epswr_figure_t *eps, hedge_arc_t *a, double dunit) { hedge_vert_t *v = a->org; if (v->show) { /* Link exits from bottom half of {a}'s box: */ r2_t p, pu, pv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); r2_t pp = hedge_draw_get_arc_record_point(&p, &pu, &pv, -0.5, -0.5, dunit); /* Link goes to edge of {v}'s box: */ r2_t q = (r2_t){{ v->pos.c[0], v->pos.c[1] }}; r2_t qq = hedge_draw_get_vert_record_point(&p, &q, dunit); double bend = 00.0; hedge_draw_struct_link(eps, &pp, &qq, bend, dunit); } } void hedge_draw_arc_left_link(epswr_figure_t *eps, hedge_arc_t *a, double dunit) { hedge_face_t *f = a->left; if (a->org->show) { /* Make link starts at bot left quarter of {a}'s box: */ r2_t p, pu, pv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); r2_t pp = hedge_draw_get_arc_record_point(&p, &pu, &pv, -0.5, +0.5, dunit); /* Link ends on edge of {f}'s box: */ r2_t q = (r2_t){{ f->ctr.c[0], f->ctr.c[1] }}; r2_t qq = hedge_draw_get_face_record_point(&p, &q, dunit); double bend = 00.0; /* Cut in half if other end is invisible: */ if (! f->show) { r2_mix(0.5, &pp, 0.5, &qq, &qq); bend = bend/4; } hedge_draw_struct_link(eps, &pp, &qq, bend, dunit); } } void hedge_draw_vert_out_link(epswr_figure_t *eps, hedge_vert_t *v, double dunit) { hedge_arc_t *a = v->out; if (v->show) { /* Link ends on bootom right corner of {a}'s box: */ r2_t q, qu, qv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &q, &qu, &qv); r2_t qq = hedge_draw_get_arc_record_point(&q, &qu, &qv, -1.0, -1.0, dunit); /* Link starts at center of vertex's box: */ r2_t p = (r2_t){{ v->pos.c[0], v->pos.c[1] }}; double bend = -0.075*r2_dist(&p, &qq); hedge_draw_struct_link(eps, &p, &qq, bend, dunit); } } void hedge_draw_face_side_link(epswr_figure_t *eps, hedge_face_t *f, double dunit) { hedge_arc_t *a = f->side; if (f->show) { /* Link ends on top quarter of left side of {a}'s box: */ r2_t q, qu, qv; double tim = hedge_draw_arc_record_TIME; hedge_draw_get_arc_point(a, tim, &q, &qu, &qv); r2_t qq = hedge_draw_get_arc_record_point(&q, &qu, &qv, +0.5, +1.00, dunit); /* Link starts at center of face's box: */ r2_t p = (r2_t){{ f->ctr.c[0], f->ctr.c[1] }}; double bend = +0.075*r2_dist(&p, &qq); /* Cut in half if arc box is invisible: */ if (! a->org->show) { r2_mix(0.5, &p, 0.5, &qq, &qq); bend = bend/4; } hedge_draw_struct_link(eps, &p, &qq, bend, dunit); } } r2_t hedge_draw_get_arc_record_point(r2_t *p, r2_t *pu, r2_t *pv, double u, double v, double dunit) { double hu = dunit*hedge_draw_arc_record_HU; double hv = dunit*hedge_draw_arc_record_HV; r2_t q; r2_mix(u*hu, pu, v*hv, pv, &q); r2_add(p, &q, &q); return q; } r2_t hedge_draw_get_vert_record_point(r2_t *p, r2_t *q, double dunit) { double d = r2_dist(p, q); double rad = dunit*hedge_draw_vert_record_RAD; double s = rad/d; r2_t qq; r2_mix(s, p, 1-s, q, &qq); return qq; } r2_t hedge_draw_get_face_record_point(r2_t *p, r2_t *q, double dunit) { double d = r2_dist(p, q); double rad = dunit*hedge_draw_face_record_RAD; double s = rad/d; r2_t qq; r2_mix(s, p, 1-s, q, &qq); return qq; } void hedge_draw_struct_link(epswr_figure_t *eps, r2_t *p, r2_t *q, double bend, double dunit) { double tim = 1.0; double rad = dunit*hedge_draw_struct_link_dot_RAD; double ahwid = dunit*hedge_draw_struct_link_arrow_WIDTH; /* Left and right width. */ double ahlen = dunit*hedge_draw_struct_link_arrow_LENGTH; hedge_draw_arrow(eps, p, q, bend, rad, tim, ahwid, ahwid, ahlen); } void hedge_draw_arrow ( epswr_figure_t *eps, r2_t *p, r2_t *q, double bend, double rad, double tim, double ahlwid, double ahrwid, double ahlen ) { r2_t p1, p2; r2_bezier_from_bend(p, q, bend, &p1, &p2); epswr_curve ( eps, p->c[0], p->c[1], p1.c[0], p1.c[1], p2.c[0], p2.c[1], q->c[0], q->c[1] ); epswr_set_pen_dashing(eps, 0,0); if (rad > 0) { epswr_dot(eps, p->c[0], p->c[1], rad, TRUE, TRUE); } /* Draws the arrowhead: */ r2_t pa, va, pb, vb; /* Endpoints of the straight shaft that carries the arrowhead. */ /* Get the position {pb} at time {tim}: */ r2_bezier_eval(0, 1, p, &p1, &p2, q, tim, &pb, &vb); /* Guess a time shortly before {tim} for the neck of the arrow: */ r2_bezier_eval(0, 1, p, &p1, &p2, q, tim-0.05, &pa, &va); epswr_arrowhead ( eps, pa.c[0], pa.c[1], pb.c[0], pb.c[1], ahlwid, ahrwid, ahlen, 1.0, TRUE, TRUE ); } /* LABELS */ void hedge_draw_face_label ( epswr_figure_t *eps, hedge_face_t *f, char *lab, double hAlign, double vAlign, double dx, double dy ) { r2_t ctr = (r2_t){{ f->ctr.c[0], f->ctr.c[1] }}; r2_t dsp = (r2_t){{ dx, dy }}; r2_t q; r2_add(&dsp, &ctr, &q); epswr_label(eps, lab, "Rg", q.c[0], q.c[1], 0, TRUE, hAlign, vAlign, TRUE, FALSE); } void hedge_draw_smudge ( epswr_figure_t *eps, r3_t *ctr, double dxmin, double dxmax, double dymin, double dymax ) { double xmin = ctr->c[0] + dxmin; double xmax = ctr->c[0] + dxmax; double ymin = ctr->c[1] + dymin; double ymax = ctr->c[1] + dymax; double x[4], y[4]; x[0] = xmin; y[0] = ymin; x[1] = xmax; y[1] = ymin; x[2] = xmax; y[2] = ymax; x[3] = xmin; y[3] = ymax; double smin = fmin(xmax - xmin, ymax - ymin); bool_t closed = TRUE; int32_t n = 4; double rad = smin/3; bool_t evenOdd = TRUE; epswr_rounded_polygon(eps, closed, x, y, n, rad, TRUE, FALSE, evenOdd); } void hedge_draw_vert_label ( epswr_figure_t *eps, hedge_vert_t *v, char *lab, double hAlign, double vAlign, double dx, double dy ) { r2_t pos = (r2_t){{ v->pos.c[0], v->pos.c[1] }}; r2_t dsp = (r2_t){{ dx, dy }}; r2_t q; r2_add(&dsp, &pos, &q); epswr_label(eps, lab, "Rg", q.c[0], q.c[1], 0, TRUE, hAlign, vAlign, TRUE, FALSE); } void hedge_draw_arc_label ( epswr_figure_t *eps, hedge_arc_t *a, double tim, char *lab, double hAlign, double vAlign, double du, double dv ) { r2_t p, pu, pv; if (debug) { fprintf(stderr, " a.org = ( %7.2f, %7.2f )\n", a->org->pos.c[0], a->org->pos.c[1]); } hedge_arc_t *b = a->next; if (debug) { fprintf(stderr, " a.dst = ( %7.2f, %7.2f )\n", b->org->pos.c[0], b->org->pos.c[1]); } hedge_draw_get_arc_point(a, tim, &p, &pu, &pv); if (debug) { fprintf(stderr, " p = ( %7.2f, %7.2f )\n", p.c[0], p.c[1]); } r2_t dp; r2_mix(du, &pu, dv, &pv, &dp); if (debug) { fprintf(stderr, " dp = ( %7.2f, %7.2f )\n", dp.c[0], dp.c[1]); } r2_t q; r2_add(&dp, &p, &q); if (debug) { fprintf(stderr, " q = ( %7.2f, %7.2f )\n", q.c[0], q.c[1]); } epswr_label(eps, lab, "Rg", q.c[0], q.c[1], 0, TRUE, hAlign, vAlign, TRUE, FALSE); } void hedge_draw_vert_ids(epswr_figure_t *eps, hedge_t *H, double rad) { if (debug) { fprintf(stderr, " > enter %s...\n", __FUNCTION__); } epswr_set_pen_color(eps, 0,0,0); epswr_set_pen_width(eps, 0.25*H->dunit); epswr_set_pen_dashing(eps, 0,0); for (uint32_t pass = 0; pass < 2; pass++) { /* Pass 0 draws vertex circles, pass 1 writes the IDs. */ if (pass == 0) { epswr_set_fill_color(eps, 1,1,1); } else { epswr_set_fill_color(eps, 0,0,0); epswr_set_label_font(eps, "Courier-Bold", 4*rad); } for (uint32_t kv = 0; kv < H->nv; kv++) { r3_t *p = &(H->V.e[kv]->pos); uint32_t id = (uint32_t)H->V.e[kv]->id; if (debug) { fprintf(stderr, " v%02d id = %02d\n", kv, id); } assert(kv == id); if (pass == 0) { epswr_dot(eps, p->c[0], p->c[1], rad, TRUE, TRUE); } else { char *txid = jsprintf("%02d", id); epswr_label(eps, txid,"0", p->c[0], p->c[1], 0.0, TRUE, 0.5,0.5, TRUE,FALSE); } } } if (debug) { fprintf(stderr, " < exit %s\n", __FUNCTION__); } } void hedge_draw_edge_ids(epswr_figure_t *eps, hedge_t *H, double tim, double dsp, double hsz, double vsz) { if (debug) { fprintf(stderr, " > enter %s...\n", __FUNCTION__); } epswr_set_pen_color(eps, 0,0,0); epswr_set_pen_width(eps, 0.25*H->dunit); epswr_set_pen_dashing(eps, 0,0); for (uint32_t pass = 0; pass < 2; pass++) { /* Pass 0 draws rectangles, pass 1 writes the IDs into them. */ if (pass == 0) { epswr_set_fill_color(eps, 1,1,0); } else { epswr_set_fill_color(eps, 0,0,0); epswr_set_label_font(eps, "Courier-Bold", 3.00*vsz); } for (int32_t ka = 0; ka < H->na; ka += 2) { hedge_arc_t *a = H->A.e[ka]; uint32_t aid = (uint32_t)a->id; assert(ka == aid); if (debug) { fprintf(stderr, " H.A[%02d] = %02d:%d\n", ka, aid/2, aid%2); } /* Get point {p} tangent dir {pu}, left dir {pv} at {tim} of the way along edge: */ r2_t p, pu; hedge_draw_get_arc_point(a, tim, &p, &pu, NULL); r2_t pv = (r2_t){{ -pu.c[1], +pu.c[0] }}; if (debug) { r2_gen_print(stderr, &p, "%.2f", " p = ( ", " ", " )"); r2_gen_print(stderr, &pu, "%.2f", " pu = ( ", " ", " )\n"); r2_gen_print(stderr, &pv, "%.2f", " pv = ( ", " ", " )\n"); } double rot = atan2(pu.c[1], pu.c[0])*180/M_PI; r2_t q; r2_mix(1.0, &p, dsp, &pv, &q); if (pass == 0) { epswr_box(eps, q.c[0], q.c[1], hsz,vsz, rot, FALSE, TRUE); } else { char *txid = jsprintf("%02d", aid/2); epswr_label(eps, txid,"0", q.c[0], q.c[1], rot, TRUE, 0.5,0.5, TRUE,FALSE); } } } if (debug) { fprintf(stderr, " < exit %s\n", __FUNCTION__); } } void hedge_draw_mesh(epswr_figure_t *eps, hedge_t *H, bool_t ghosts) { double dunit = H->dunit; for (uint32_t kf = 0; kf < H->nf; kf++) { double R = 0.900 + (kf % 3)* 0.050; double G = 0.900 + ((kf + 1) % 5) * 0.020; double B = 0.900 + ((kf + 2) % 4) * 0.025; epswr_set_fill_color(eps, R, G, B); hedge_fill_face(eps, H->F.e[kf]); } for (uint32_t kv = 0; kv < H->nv; kv++) { epswr_set_fill_color(eps, 0.000,0.000,0.000); hedge_draw_vert(eps, H->V.e[kv], dunit); } double ghdash = (ghosts ? 3.0*dunit : -1.0); for (int32_t ka = 0; ka < H->na; ka += 2) { epswr_set_fill_color(eps, 0.000,0.000,0.000); hedge_draw_edge(eps, H->A.e[ka], ghdash); } } void hedge_draw_get_plot_bounds(hedge_t *H, double *xmin_P, double *xmax_P, double *ymin_P, double *ymax_P) { double cmin[2], cmax[2]; for (uint32_t i = 0; i < 2; i++) { cmin[i] = +INF; cmax[i] = -INF; } for (uint32_t ka = 0; ka < H->na; ka++) { hedge_arc_t *a = H->A.e[ka]; hedge_vert_t *org = a->org; if (org->show) { hedge_arc_t *b = a->twin; hedge_vert_t *dst = b->org; if (org->show) { for (uint32_t i = 0; i < 2; i++) { double ci = org->pos.c[i]; if (ci < cmin[i]) { cmin[i] = ci; } if (ci > cmax[i]) { cmax[i] = ci; } if (! dst->show) { /* Include the midpoint: */ ci = (org->pos.c[i] + dst->pos.c[i])/2; double cim = ci - fabs(a->bend); if (cim < cmin[i]) { cmin[i] = cim; } double cip = ci + fabs(a->bend); if (cip > cmax[i]) { cmax[i] = cip; } } } } } } for (uint32_t kf = 0; kf < H->nf; kf++) { hedge_face_t *f = H->F.e[kf]; if (f->show) { for (uint32_t i = 0; i < 2; i++) { double ci = f->ctr.c[i]; if (ci < cmin[i]) { cmin[i] = ci; } if (ci > cmax[i]) { cmax[i] = ci; } } } } for (uint32_t i = 0; i < 2; i++) { /* Expand to account for node size: */ assert(cmin[i] <= cmax[i]); cmin[i] -= H->dunit*6.0; cmax[i] += H->dunit*6.0; } (*xmin_P) = cmin[0]; (*xmax_P) = cmax[0]; (*ymin_P) = cmin[1]; (*ymax_P) = cmax[1]; }