/* See {hedge.h}. */ /* Copyright (C) 2023 Jorge Stolfi, UNICAMP */ /* Last edited on 2025-05-07 17:21:21 by stolfi */ #include #include #include #include #include #include #include #include #include #define debug TRUE #define valloc(n, T) \ ((T*)notnull(calloc((n), sizeof(T)), "no mem")) void hedge_bad(hedge_vert_t *v, hedge_arc_t *a, hedge_arc_t *b, hedge_face_t *f, hedge_face_t *g, char* msg); /* Prints {msg}, then {v}, {a}, {b}, {f}, and/or {g} if they are not NULL. */ void hedge_err(hedge_vert_t *v, hedge_arc_t *a, hedge_arc_t *b, hedge_face_t *f, hedge_face_t *g, char* msg); /* Prints {msg}, then {v}, {a}, {b}, {f}, and/or {g} if they are not NULL. Then bombs out. */ hedge_t *hedge_new(int32_t nf_alloc, int32_t ne_alloc, int32_t nv_alloc) { hedge_t *H = valloc(1, hedge_t); H->F = hedge_face_vec_new((uint32_t)nf_alloc); H->nf = 0; H->A = hedge_arc_vec_new(2*(uint32_t)ne_alloc); H->na = 0; H->V = hedge_vert_vec_new((uint32_t)nv_alloc); H->nv = 0; return H; } hedge_vert_t *hedge_add_vert(hedge_t *H, double X, double Y, double Z, bool_t show) { hedge_vert_t *v = valloc(1, hedge_vert_t); v->pos = (r3_t){{ X, Y, Z }}; v->out = NULL; v->show = show; v->id = H->nv; hedge_vert_vec_expand(&(H->V), H->nv); H->V.e[H->nv]= v; H->nv++; return v; } hedge_arc_t *hedge_add_edge ( hedge_t *H, hedge_vert_t *org, hedge_vert_t *dst, double bend ) { hedge_arc_t *a = valloc(1, hedge_arc_t); a->org = org; a->left = NULL; a->next = NULL; a->bend = +bend + 2.0; a->id = H->na; org->out = a; hedge_arc_t *b = valloc(1, hedge_arc_t); b->org = dst; b->left = NULL; b->next = NULL; b->bend = -bend + 2.0; b->id = H->na + 1; dst->out = b; a->twin = b; b->twin = a; hedge_arc_vec_expand(&(H->A), H->na+1); H->A.e[H->na]= a; H->A.e[H->na+1]= b; H->na += 2; return a; } hedge_face_t *hedge_add_face(hedge_t *H, double X, double Y, double Z, bool_t show, hedge_arc_t *a) { hedge_face_t *f = valloc(1, hedge_face_t); f->ctr = (r3_t){{ X, Y, Z }}; f->side = NULL; f->show = show; f->id = H->nf; hedge_face_vec_expand(&(H->F), H->nf); H->F.e[H->nf]= f; H->nf++; if (a != NULL) { hedge_set_lefts(a, f); } return f; } void hedge_set_next(hedge_arc_t *a, hedge_arc_t *b) { if (a->next != NULL) { hedge_err(NULL, a,a->next, NULL,NULL, "{a.next} already defined"); } if (debug) { fprintf(stderr, " e%02d:%d.next = e%02d:%d\n", a->id/2, a->id%2, b->id/2, b->id%2); } if (a->left != NULL) { hedge_err(NULL, a,NULL, a->left,NULL, "{a.left} is not {NULL}"); } if (b->left != NULL) { hedge_err(NULL, b,NULL, b->left,NULL, "{b.left} is not {NULL}"); } a->next = b; } void hedge_set_lefts(hedge_arc_t *a, hedge_face_t *f) { hedge_arc_t *e = a; do { if (e->left != NULL) { hedge_err(NULL, e,NULL, e->left,NULL, "{e.left} is not {NULL}"); } e->left = f; if (e->next == NULL) { hedge_err(NULL, e,NULL, NULL,NULL, "{e.next} is {NULL}"); } if (debug) { fprintf(stderr, " e%02d:%d.left = f%02d\n", e->id/2, e->id%2, f->id); } e = e->next; } while (e != a); if (f->side != NULL) { hedge_err(NULL, f->side,NULL, f,NULL, "{f.side} is not {NULL}"); } if (debug) { fprintf(stderr, " f%02d.side = e%02d:%d\n", f->id, a->id/2, a->id%2); } f->side = a; } void hedge_check_topology(hedge_t *H) { /* Consistency of arc {twin}: */ if (debug) { fprintf(stderr, "checking arcs...\n"); } bool_t ok = TRUE; for (uint32_t ka = 0; ka < H->na; ka++) { hedge_arc_t *a = H->A.e[ka]; if (a == NULL) { hedge_err(NULL, NULL,NULL, NULL,NULL, "{NULL} in arc table"); } if (a->id != ka) { hedge_bad(NULL, a,NULL, NULL,NULL, "arc ID is not its index in table"); ok = FALSE; } hedge_arc_t *b = a->twin; if (b == NULL) { hedge_err(NULL, a,NULL, NULL,NULL, "{a.twin} is {NULL}"); } if (a == b) { hedge_bad(NULL, a,NULL, NULL,NULL, "arc is own {twin}"); ok = FALSE; } if (b->twin == NULL) { hedge_err(NULL, a,b, NULL,NULL, "{a.twin.twin} is {NULL}"); } if (b->twin != a) { hedge_bad(NULL, a,b, NULL,NULL, "{a.twin.twin} is not {a}"); ok = FALSE; } } /* Consistency of face {side} and arc {next}: */ if (debug) { fprintf(stderr, "checking faces...\n"); } for (uint32_t kf = 0; kf < H->nf; kf++) { hedge_face_t *f = H->F.e[kf]; if (f == NULL) { hedge_err(NULL, NULL,NULL, NULL,NULL, "{NULL} in face table"); } if (f->id != kf) { hedge_bad(NULL, NULL,NULL, f,NULL, "face ID is not its index in table"); ok = FALSE; } hedge_arc_t *a = f->side; if (a == NULL) { hedge_err(NULL, NULL,NULL, f,NULL, "{f.side} is {NULL}"); } do { if (a->left != f) { hedge_bad(NULL, a,NULL, f,NULL, "{f.side.next^k.left} is not {f}"); ok = FALSE; } if (a->next == NULL) { hedge_err(NULL, a,NULL, NULL,NULL, "{a.next} is {NULL}"); } a = a->next; } while (a != f->side); } /* Consistency of vertex {out} and arc {turn}: */ if (debug) { fprintf(stderr, "checking vertices...\n"); } for (uint32_t kv = 0; kv < H->nv; kv++) { if (debug) { fprintf(stderr, " v%02d\n", kv); } hedge_vert_t *v = H->V.e[kv]; if (v == NULL) { hedge_err(NULL, NULL,NULL, NULL,NULL, "{NULL} in vertex table"); } if (v->id != kv) { hedge_bad(v, NULL,NULL, NULL,NULL, "vertex ID is not its index in table"); ok = FALSE; } hedge_arc_t *a = v->out; if (a == NULL) { hedge_err(v, NULL,NULL, NULL,NULL, "{v.out} is {NULL}"); } do { if (debug) { fprintf(stderr, " e%02d:%d", a->id/2, a->id%2); } if (a->org != v) { hedge_bad(v, a,NULL, NULL,NULL, "{v.out(.twin.next)^k.org} is not {v}"); ok = FALSE; } hedge_arc_t *b = a->twin; if (b == NULL) { hedge_err(NULL, a,NULL, NULL,NULL, "{a.twin} is {NULL}"); } if (debug) { fprintf(stderr, " .twin = e%02d:%d", b->id/2, b->id%2); } hedge_arc_t *c = b->next; if (c == NULL) { hedge_err(NULL, b,NULL, NULL,NULL, "{b.next} is {NULL}"); } if (debug) { fprintf(stderr, " .next = e%02d:%d\n", c->id/2, c->id%2); } a = c; } while (a != v->out); } assert(ok); } void hedge_bad(hedge_vert_t *v, hedge_arc_t *a, hedge_arc_t *b, hedge_face_t *f, hedge_face_t *g, char* msg) { fprintf(stderr, "** error %s", msg); if (v != NULL) { fprintf(stderr, " v%02d", v->id); } if (a != NULL) { fprintf(stderr, " e%02d:%d", a->id/2, a->id%2); } if (b != NULL) { fprintf(stderr, " e%02d:%d", b->id/2, b->id%2); } if (f != NULL) { fprintf(stderr, " f%02d", f->id); } if (g != NULL) { fprintf(stderr, " f%02d", g->id); } fprintf(stderr, "\n"); } void hedge_err(hedge_vert_t *v, hedge_arc_t *a, hedge_arc_t *b, hedge_face_t *f, hedge_face_t *g, char* msg) { hedge_bad(v, a, b, f, g, msg); assert(FALSE); } vec_typeimpl(hedge_face_vec_t, hedge_face_vec, hedge_face_t*); vec_typeimpl(hedge_arc_vec_t, hedge_arc_vec, hedge_arc_t*); vec_typeimpl(hedge_vert_vec_t, hedge_vert_vec, hedge_vert_t*);