/* Last edited on 2024-12-21 14:02:12 by stolfi */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define debug FALSE void toposlice_skip_find_crossing_edges ( hedge_t *H, hedge_face_t *F, double Z_plane[], hedge_arc_t *e_left[], hedge_arc_t *e_right[], int32_t *nF_P ); /* Computes the degree {nF} of face {F}. Also, for {k} in {0..1}, finds the edges {e_left[k]}, {e_right[]} on the left and right sides of {F} that cross plane {k} assumed to be at height {Z_plane[k]}. */ void toposlice_skip_set_links ( hedge_t *H, hedge_face_t *F, hedge_arc_t *e_left[], hedge_arc_t *e_right[], int32_t phase, hedge_arc_t *a[], hedge_arc_t *b[], int32_t *nsk_P ); /* Given the left and right crossing sides of {F} {e_left[k],e_right[k]}, upward oriented, and the {phase} of the drawing, determines the number {nsk} of {.skip} pointers to draw, and sets the origin and destination arcs of each pointer in {a[k]}, {b[k]} for {k} in {0..nsk-1}. For phases 0 or 1, the first skip link will leave {e_left[0]}; for phase 2, it will leave {e_left[1]}. For phase 0, every {.skip} link will be the same as {.enext}. For phases 1 and 2, the link from {e_left[0]} will jump from {e_right[0]} and all intermediate links will be omitted. */ void toposlice_skip_fig_draw_plane ( epswr_figure_t *eps, double xmin, double xmax, double Y, double R, double G, double B ); /* Draws the profile of a slicing plane at ordinate {Y} and abscissas {[xmin _ xmax]}, with color {R,G,B}. */ void toposlice_skip_draw_arc ( epswr_figure_t *eps, hedge_arc_t *e, double tim, char *lab, double hAlign, double vAlign, double dx, double dy, double dunit ); /* Draws the edge {e} in red, with arrowhed and label {lab} with relative position {dx} along the edge and {dy} to the left of it. */ void toposlice_skip_draw_skip_link ( epswr_figure_t *eps, hedge_arc_t *a, hedge_arc_t *b, bool_t trav, double dunit ); /* Draws a skip link pointing from arc {a} to ac {b}, with bending parameter {bend}. The color and dashing depend on the parameter {trav}. */ double toposlice_skip_get_link_bend(hedge_arc_t *a, hedge_arc_t *b); /* Computes a suitable {bend} parameter for the skip link from the midpoint of {a} to the midpoint of {b}. */ hedge_t *toposlice_skip_fig_create_mesh(void); /* Creates the half-edge mesh structure for the figure. */ #define sex hedge_set_next void toposlice_skip_fig_make(char *name, int32_t phase) { if (debug) { fprintf(stderr, " > enter %s...\n", __FUNCTION__); } hedge_t *H = toposlice_skip_fig_create_mesh(); double dunit = H->dunit; double xmin, xmax, ymin, ymax; /* Figure range in mm. */ hedge_draw_get_plot_bounds(H, &xmin, &xmax, &ymin, &ymax); double hsz = (xmax - xmin)*epswr_pt_per_mm; double vsz = (ymax - ymin)*epswr_pt_per_mm; double mrg = 2*epswr_pt_per_mm; epswr_figure_t *eps = epswr_new_named_figure("out", NULL, name, -1, NULL, hsz, vsz, mrg,mrg,mrg,mrg, TRUE); epswr_set_client_window(eps, xmin, xmax, ymin, ymax); epswr_set_label_font(eps, "Times-Italic", 120); if (debug) { fprintf(stderr, "drawing the slicing planes...\n"); } double Z_plane[2] = { 478, 732 }; if ((phase == 0) || (phase == 1)) { toposlice_skip_fig_draw_plane(eps, xmin, xmax, Z_plane[0], 0.200,0.400,0.000); } else if (phase == 2) { toposlice_skip_fig_draw_plane(eps, xmin, xmax, Z_plane[0], 0.700,0.800,0.600); toposlice_skip_fig_draw_plane(eps, xmin, xmax, Z_plane[1], 0.200,0.400,0.000); } if (debug) { fprintf(stderr, "drawing the mesh...\n"); } epswr_set_pen(eps, 0,0,0, 1.00, 0,0); epswr_set_fill_color(eps, 0,0,0); bool_t ghosts = TRUE; /* Irrelevant since there are no ghost edges. */ hedge_draw_mesh(eps, H, ghosts); if (debug) { fprintf(stderr, "finding the plane-crossing edges {e',e''} for each plane...\n"); } hedge_face_t *F = H->F.e[0]; /* The main face, and its size: */ int32_t nF = 0; /* The degree of {F}: */ hedge_arc_t *e_left[2]; /* Up-crossing edhes on left side of {F}. */ hedge_arc_t *e_right[2]; /* Up-crossing edhes on right side of {F}. */ toposlice_skip_find_crossing_edges(H, F, Z_plane, e_left, e_right, &nF); if (debug) { fprintf(stderr, "building the {.skip} links...\n"); } hedge_arc_t *a[nF]; /* Origin arc of each skip link. */ hedge_arc_t *b[nF]; /* Destination arc of each skip link. */ int32_t nsk; /* Skip links are {a[k] --> b[k]} for {k} in {0..nsk-1}. */ toposlice_skip_set_links(H, F, e_left, e_right, phase, a, b, &nsk); if (debug) { fprintf(stderr, "drawing the {.skip} links...\n"); } int32_t nsteps[3] = { 4, 0, 5 }; /* Steps of inner loop per {phase}. */ for (uint32_t k = 0; k < nsk; k++) { bool_t trav = k < nsteps[phase]; toposlice_skip_draw_skip_link(eps, a[k], b[k], trav, dunit); } if (debug) { fprintf(stderr, "drawing the current edge {e} and the plane-crossing edges {e',e''}...\n"); } if (phase == 0) { toposlice_skip_draw_arc(eps, e_left[0], 0.80, "a", 1.0,1.0, +5,+25, dunit); hedge_arc_t *e_cur = b[nsteps[phase]-1]; toposlice_skip_draw_arc(eps, e_cur, 0.80, "e", 0.0,1.0, -7,-3, dunit); } else if (phase == 1) { toposlice_skip_draw_arc(eps, e_left[0], 0.80, "a", 1.0,1.0, +5,+17, dunit); toposlice_skip_draw_arc(eps, e_right[0], 0.85, "e", 0.0,1.0, 0,-8, dunit); } else if (phase == 2) { toposlice_skip_draw_arc(eps, e_left[1], 0.75, "a", 1.0,0.0, -17,+7, dunit); hedge_arc_t *e_cur = b[nsteps[phase]-1]; toposlice_skip_draw_arc(eps, e_cur, 0.85, "e", 0.0,0.5, -17,-12, dunit); } else { assert(FALSE); } epswr_end_figure(eps); if (debug) { fprintf(stderr, " < exit %s...\n", __FUNCTION__); } } void toposlice_skip_set_links ( hedge_t *H, hedge_face_t *F, hedge_arc_t *e_left[], hedge_arc_t *e_right[], int32_t phase, hedge_arc_t *a[], hedge_arc_t *b[], int32_t *nsk_P ) { hedge_arc_t *e_start; /* Skip links are all {.next} except that from {a_jump} jumps to {b_jump}. */ hedge_arc_t *a_jump; hedge_arc_t *b_jump; if (phase == 0) { /* Starts at plane 0, all skip links are {.next}: */ e_start = e_left[0]->twin; a_jump = NULL; b_jump = NULL; } else if (phase == 1) { /* Starts at plane 0, skips part below {Z_plane[0]}: */ e_start = e_left[0]->twin; a_jump = e_left[0]->twin; b_jump = e_right[0]; } else if (phase == 2) { /* Starts at plane 1, skips part below {Z_plane[0]}: */ e_start = e_left[1]->twin; a_jump = e_left[0]->twin; b_jump = e_right[0]; } else { assert(FALSE); } hedge_arc_t *e0 = e_start; hedge_arc_t *e1 = e0; int32_t nsk = 0; do { a[nsk] = e1; if (e1 == a_jump) { b[nsk] = b_jump; } else { b[nsk] = e1->next; } e1 = b[nsk]; nsk++; } while (e1 != e0); (*nsk_P) = nsk; } void toposlice_skip_find_crossing_edges ( hedge_t *H, hedge_face_t *F, double Z_plane[], hedge_arc_t *e_left[], hedge_arc_t *e_right[], int32_t *nF_P ) { int32_t nF = 0; /* The main face, and its size: */ hedge_arc_t *e0 = F->side; hedge_arc_t *e1 = e0; do { double Z_org = e1->org->pos.c[1]; double Z_dst = e1->twin->org->pos.c[1]; for (uint32_t k = 0; k < 2; k++) { if ((Z_org > Z_plane[k]) && (Z_dst < Z_plane[k])) { e_left[k] = e1->twin; } if ((Z_org < Z_plane[k]) && (Z_dst > Z_plane[k])) { e_right[k] = e1; } } e1 = e1->next; nF++; } while (e1 != e0); (*nF_P) = nF; } void toposlice_skip_draw_arc ( epswr_figure_t *eps, hedge_arc_t *e, double tim, char *lab, double hAlign, double vAlign, double dx, double dy, double dunit ) { double R = 1.000, G = 0.000, B = 0.000; epswr_set_pen_color(eps, R,G,B); epswr_set_fill_color(eps, R,G,B); epswr_set_pen_width(eps, 1.25*dunit); epswr_set_pen_dashing(eps, 0,0); bool_t ghdash = 0; /* Irrelevant since there are no ghost edges. */ hedge_draw_edge(eps, e, ghdash); hedge_draw_arc_arrowhead(eps, e, tim, dunit); if (lab != NULL) { epswr_set_pen_color(eps, 0,0,0); epswr_set_fill_color(eps, 0,0,0); hedge_draw_arc_label(eps, e, tim, lab, hAlign, vAlign, dx, dy); hedge_draw_vert(eps, e->org, dunit); hedge_draw_vert(eps, e->twin->org, dunit); } } void toposlice_skip_fig_draw_plane ( epswr_figure_t *eps, double xmin, double xmax, double Y, double R, double G, double B ) { epswr_set_pen(eps, R,G,B, 3.00, 0,0); epswr_segment(eps, xmin,Y, xmax,Y); } void toposlice_skip_draw_skip_link ( epswr_figure_t *eps, hedge_arc_t *a, hedge_arc_t *b, bool_t trav, double dunit ) { double R, G, B; double dlen, dgap; /* Dashing parameters. */ double wid; /* Pen width. */ if (trav) { R = 0.900; G = 0.000; B = 0.400; wid = 1.00; dlen = 3.0; dgap = 3.0; } else { R = 0.000; G = 0.400; B = 0.900; wid = 0.85; dlen = 1.5; dgap = 2.0; } epswr_set_pen_color(eps, R,G,B); epswr_set_fill_color(eps, R,G,B); epswr_set_pen_width(eps, wid*dunit); epswr_set_pen_dashing(eps, dlen*dunit, dgap*dunit); r3_t a_mid; r3_mix(0.5, &(a->org->pos), 0.5, &(a->twin->org->pos), &a_mid); r3_t b_mid; r3_mix(0.5, &(b->org->pos), 0.5, &(b->twin->org->pos), &b_mid); r2_t am = (r2_t){{ a_mid.c[0], a_mid.c[1]}}; r2_t bm = (r2_t){{ b_mid.c[0], b_mid.c[1]}}; double bend = toposlice_skip_get_link_bend(a, b); double rad = dunit*0.75; double ahwid = dunit*2.0; double ahlen = dunit*4.5; hedge_draw_arrow(eps, &am, &bm, bend, rad, 0.70, ahwid, 0.0, ahlen); } double toposlice_skip_get_link_bend(hedge_arc_t *a, hedge_arc_t *b) { double bend = NAN; if (a->twin->org != b->org) { /* Arcs are not consecutive. A constant bend probbaly will do: */ bend = 15.0; } else { /* Arcs are consecutive. The bend depends on the angle between the,: */ r3_t *p0 = &(a->org->pos); r3_t *p1 = &(b->org->pos); r3_t *p2 = &(b->twin->org->pos); r2_t u = (r2_t){{ p1->c[0] - p0->c[0], p1->c[1] - p0->c[1] }}; r2_t v = (r2_t){{ p2->c[0] - p1->c[0], p2->c[1] - p1->c[1] }}; double cr = r2_det(&u, &v); if (cr >= 0) { /* The common vertex is convex. Constant bend should do: */ bend = 15; } else { r2_t w; r2_add(&u, &v, &w); double wm = r2_dir(&w, &w); assert(wm > 0); r2_t s; r2_sub(&u, &v, &s); double h = r2_det(&w, &s); assert(h > 0); bend = 10 + 0.5*h; } } return bend; } hedge_t *toposlice_skip_fig_create_mesh(void) { if (debug) { fprintf(stderr, " > enter %s...\n", __FUNCTION__); } hedge_t *H = hedge_new(100, 100, 100); H->dunit = 3.0; hedge_arc_t **a = H->A.e; hedge_vert_t **v = H->V.e; /* Vertices: */ bool_t vvis = FALSE; /* Do not draw oyt-of-frame vertices. */ (void)hedge_add_vert(H, 412, 290, 0, TRUE); /* v00 */ (void)hedge_add_vert(H, 540, 340, 0, TRUE); /* v01 */ (void)hedge_add_vert(H, 612, 440, 0, TRUE); /* v02 */ (void)hedge_add_vert(H, 630, 540, 0, TRUE); /* v03 */ (void)hedge_add_vert(H, 600, 630, 0, TRUE); /* v04 */ (void)hedge_add_vert(H, 622, 700, 0, TRUE); /* v05 */ (void)hedge_add_vert(H, 530, 700, 0, TRUE); /* v06 */ (void)hedge_add_vert(H, 470, 810, 0, TRUE); /* v07 */ (void)hedge_add_vert(H, 480, 880, 0, TRUE); /* v08 */ (void)hedge_add_vert(H, 300, 880, 0, TRUE); /* v09 */ (void)hedge_add_vert(H, 315, 780, 0, TRUE); /* v10 */ (void)hedge_add_vert(H, 202, 693, 0, TRUE); /* v11 */ (void)hedge_add_vert(H, 225, 606, 0, TRUE); /* v12 */ (void)hedge_add_vert(H, 250, 570, 0, TRUE); /* v13 */ (void)hedge_add_vert(H, 227, 456, 0, TRUE); /* v14 */ (void)hedge_add_vert(H, 305, 370, 0, TRUE); /* v15 */ (void)hedge_add_vert(H, 330, 290, 0, TRUE); /* v16 */ (void)hedge_add_vert(H, 530, 200, 0, vvis); /* v17 */ (void)hedge_add_vert(H, 730, 259, 0, vvis); /* v18 */ (void)hedge_add_vert(H, 730, 370, 0, vvis); /* v19 */ (void)hedge_add_vert(H, 730, 518, 0, vvis); /* v20 */ (void)hedge_add_vert(H, 730, 606, 0, vvis); /* v21 */ (void)hedge_add_vert(H, 730, 673, 0, vvis); /* v22 */ (void)hedge_add_vert(H, 730, 806, 0, vvis); /* v23 */ (void)hedge_add_vert(H, 730, 976, 0, vvis); /* v24 */ (void)hedge_add_vert(H, 562, 999, 0, vvis); /* v25 */ (void)hedge_add_vert(H, 262, 999, 0, vvis); /* v26 */ (void)hedge_add_vert(H, 152, 999, 0, vvis); /* v27 */ (void)hedge_add_vert(H, 90, 832, 0, vvis); /* v28 */ (void)hedge_add_vert(H, 90, 658, 0, vvis); /* v29 */ (void)hedge_add_vert(H, 90, 400, 0, vvis); /* v30 */ (void)hedge_add_vert(H, 90, 236, 0, vvis); /* v31 */ (void)hedge_add_vert(H, 227, 200, 0, vvis); /* v32 */ (void)hedge_add_vert(H, 387, 200, 0, vvis); /* v33 */ (void)hedge_add_vert(H, 90, 550, 0, vvis); /* v34 */ /* Edges: */ (void)hedge_add_edge(H, v00, v01, 0); /* e00 */ (void)hedge_add_edge(H, v01, v02, 0); /* e01 */ (void)hedge_add_edge(H, v02, v03, 0); /* e02 */ (void)hedge_add_edge(H, v03, v04, 0); /* e03 */ (void)hedge_add_edge(H, v04, v05, 0); /* e04 */ (void)hedge_add_edge(H, v05, v06, 0); /* e05 */ (void)hedge_add_edge(H, v06, v07, 0); /* e06 */ (void)hedge_add_edge(H, v07, v08, 0); /* e07 */ (void)hedge_add_edge(H, v08, v09, 0); /* e08 */ (void)hedge_add_edge(H, v09, v10, 0); /* e09 */ (void)hedge_add_edge(H, v10, v11, 0); /* e10 */ (void)hedge_add_edge(H, v11, v12, 0); /* e11 */ (void)hedge_add_edge(H, v12, v13, 0); /* e12 */ (void)hedge_add_edge(H, v13, v14, 0); /* e13 */ (void)hedge_add_edge(H, v14, v15, 0); /* e14 */ (void)hedge_add_edge(H, v15, v16, 0); /* e15 */ (void)hedge_add_edge(H, v16, v00, 0); /* e16 */ (void)hedge_add_edge(H, v00, v17, 0); /* e17 */ (void)hedge_add_edge(H, v01, v17, 0); /* e18 */ (void)hedge_add_edge(H, v01, v18, 0); /* e19 */ (void)hedge_add_edge(H, v02, v19, 0); /* e20 */ (void)hedge_add_edge(H, v03, v20, 0); /* e21 */ (void)hedge_add_edge(H, v04, v21, 0); /* e22 */ (void)hedge_add_edge(H, v05, v22, 0); /* e23 */ (void)hedge_add_edge(H, v06, v23, 0); /* e24 */ (void)hedge_add_edge(H, v07, v23, 0); /* e25 */ (void)hedge_add_edge(H, v07, v24, 0); /* e26 */ (void)hedge_add_edge(H, v08, v25, 0); /* e27 */ (void)hedge_add_edge(H, v09, v26, 0); /* e28 */ (void)hedge_add_edge(H, v10, v27, 0); /* e29 */ (void)hedge_add_edge(H, v10, v28, 0); /* e30 */ (void)hedge_add_edge(H, v11, v29, 0); /* e31 */ (void)hedge_add_edge(H, v12, v29, 0); /* e32 */ (void)hedge_add_edge(H, v13, v34, 0); /* e33 */ /* Patch! */ (void)hedge_add_edge(H, v14, v30, 0); /* e34 */ (void)hedge_add_edge(H, v14, v31, 0); /* e35 */ (void)hedge_add_edge(H, v15, v31, 0); /* e36 */ (void)hedge_add_edge(H, v16, v32, 0); /* e37 */ (void)hedge_add_edge(H, v00, v33, 0); /* e38 */ (void)hedge_add_edge(H, v17, v18, 0); /* e39 */ (void)hedge_add_edge(H, v18, v19, 0); /* e40 */ (void)hedge_add_edge(H, v19, v20, 0); /* e41 */ (void)hedge_add_edge(H, v20, v21, 0); /* e42 */ (void)hedge_add_edge(H, v21, v22, 0); /* e43 */ (void)hedge_add_edge(H, v22, v23, 0); /* e44 */ (void)hedge_add_edge(H, v23, v24, 0); /* e45 */ (void)hedge_add_edge(H, v24, v25, 0); /* e46 */ (void)hedge_add_edge(H, v25, v26, 0); /* e47 */ (void)hedge_add_edge(H, v26, v27, 0); /* e48 */ (void)hedge_add_edge(H, v27, v28, 0); /* e49 */ (void)hedge_add_edge(H, v28, v29, 0); /* e50 */ (void)hedge_add_edge(H, v29, v34, 0); /* e51 */ (void)hedge_add_edge(H, v30, v31, 0); /* e52 */ (void)hedge_add_edge(H, v31, v32, 0); /* e53 */ (void)hedge_add_edge(H, v32, v33, 0); /* e54 */ (void)hedge_add_edge(H, v33, v17, 0); /* e55 */ (void)hedge_add_edge(H, v34, v30, 0); /* e56 */ /* Patch! */ /* Faces: */ bool_t fvis = vvis; /* f00 */ for (uint32_t i = 0; i < 17; i++) { hedge_arc_t *ei = H->A.e[2*i]; hedge_arc_t *ej = H->A.e[2*((i+1)%17)]; sex(ei, ej); } (void)hedge_add_face(H, 0, 0, 0, fvis, e00); /* f01 */ sex( e00->twin, e17 ); sex( e17, e18->twin ); sex( e18->twin, e00->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e00->twin); /* f02 */ sex( e18, e39 ); sex( e39, e19->twin ); sex( e19->twin, e18 ); (void)hedge_add_face(H, 0, 0, 0, fvis, e18); /* f03 */ sex( e01->twin, e19 ); sex( e19, e40 ); sex( e40, e20->twin ); sex( e20->twin, e01->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e01->twin); /* f04 */ sex( e02->twin, e20 ); sex( e20, e41 ); sex( e41, e21->twin ); sex( e21->twin, e02->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e02->twin); /* f05 */ sex( e03->twin, e21 ); sex( e21, e42 ); sex( e42, e22->twin ); sex( e22->twin, e03->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e03->twin); /* f06 */ sex( e04->twin, e22 ); sex( e22, e43 ); sex( e43, e23->twin ); sex( e23->twin, e04->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e04->twin); /* f07 */ sex( e05->twin, e23 ); sex( e23, e44 ); sex( e44, e24->twin ); sex( e24->twin, e05->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e05->twin); /* f08 */ sex( e06->twin, e24 ); sex( e24, e25->twin ); sex( e25->twin, e06->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e06->twin); /* f09 */ sex( e25, e45 ); sex( e45, e26->twin ); sex( e26->twin, e25 ); (void)hedge_add_face(H, 0, 0, 0, fvis, e25); /* f10 */ sex( e07->twin, e26 ); sex( e26, e46 ); sex( e46, e27->twin ); sex( e27->twin, e07->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e07->twin); /* f11 */ sex( e08->twin, e27 ); sex( e27, e47 ); sex( e47, e28->twin ); sex( e28->twin, e08->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e08->twin); /* f12 */ sex( e09->twin, e28 ); sex( e28, e48 ); sex( e48, e29->twin ); sex( e29->twin, e09->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e09->twin); /* f13 */ sex( e29, e49 ); sex( e49, e30->twin ); sex( e30->twin, e29 ); (void)hedge_add_face(H, 0, 0, 0, fvis, e29); /* f14 */ sex( e10->twin, e30 ); sex( e30, e50 ); sex( e50, e31->twin ); sex( e31->twin, e10->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e10->twin); /* f15 */ sex( e11->twin, e31 ); sex( e31, e32->twin ); sex( e32->twin, e11->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e11->twin); /* f16 */ sex( e12->twin, e32 ); sex( e32, e51 ); sex( e51, e33->twin ); sex( e33->twin, e12->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e12->twin); /* f17 */ sex( e13->twin, e33 ); sex( e33, e56 ); /* Patch! */ sex( e56, e34->twin ); /* Patch! */ sex( e34->twin, e13->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e13->twin); /* f18 */ sex( e34, e52 ); sex( e52, e35->twin ); sex( e35->twin, e34 ); (void)hedge_add_face(H, 0, 0, 0, fvis, e34); /* f19 */ sex( e14->twin, e35 ); sex( e35, e36->twin ); sex( e36->twin, e14->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e14->twin); /* f20 */ sex( e15->twin, e36 ); sex( e36, e53 ); sex( e53, e37->twin ); sex( e37->twin, e15->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e15->twin); /* f21 */ sex( e16->twin, e37 ); sex( e37, e54 ); sex( e54, e38->twin ); sex( e38->twin, e16->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e16->twin); /* f22 */ sex( e38, e55 ); sex( e55, e17->twin ); sex( e17->twin, e38 ); (void)hedge_add_face(H, 0, 0, 0, fvis, e38); /* f23 */ sex( e55->twin, e54->twin ); sex( e54->twin, e53->twin ); sex( e53->twin, e52->twin ); sex( e52->twin, e56->twin ); /* Patch! */ sex( e56->twin, e51->twin ); /* Patch! */ sex( e51->twin, e50->twin ); sex( e50->twin, e49->twin ); sex( e49->twin, e48->twin ); sex( e48->twin, e47->twin ); sex( e47->twin, e46->twin ); sex( e46->twin, e45->twin ); sex( e45->twin, e44->twin ); sex( e44->twin, e43->twin ); sex( e43->twin, e42->twin ); sex( e42->twin, e41->twin ); sex( e41->twin, e40->twin ); sex( e40->twin, e39->twin ); sex( e39->twin, e55->twin ); (void)hedge_add_face(H, 0, 0, 0, fvis, e55->twin); hedge_check_topology(H); /* Recompute face centers: */ for (uint32_t kf = 0; kf < H->nf; kf++) { hedge_face_t *f = H->F.e[kf]; r3_t ctr = (r3_t){{ 0,0,0 }}; int32_t deg = 0; hedge_arc_t *e = f->side; do { hedge_vert_t *org = e->org; r3_add(&(org->pos), &ctr, &ctr); deg++; e = e->next; } while (e != f->side); demand(deg >= 3, "face degree must be 3 or more"); r3_scale(1.0/deg, &ctr, &(f->ctr)); } if (debug) { fprintf(stderr, " < exit %s...\n", __FUNCTION__); } return H; }