/* * extrude.c - Perform the extrusion * * Written 2011 by Werner Almesberger * Copyright 2011 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /* * Known bugs: * * - negative x coordinates in shape produce overlapping faces */ #include #include #include #include "ptrude.h" #include "path.h" #include "extrude.h" static void cvt_3d(struct point *p, const struct vertex *v, double z) { p->x = v->x; p->y = v->y; p->z = z; } static void size(const struct path *p) { const struct vertex *v, *next; double s = 0, sl = 0; int n = 0; if (!debug) return; for (v = p->vertices; v; v = next) { next = v->next; if (next) s += hypot(v->x-next->x, v->y-next->y); sl += v->len; n++; } fprintf(stderr, "%d virt %g real %g\n", n, sl, s); } static void mesh(const struct path *pa, double za, const struct path *pb, double zb, void (*face)(void *data, struct point a, struct point b, struct point c), void *data) { const struct vertex *a = pa->vertices; const struct vertex *b = pb->vertices; double sa = 0, sb = 0; /* total distance traveled on path */ double da, db; struct point a3, b3, n; cvt_3d(&a3, a, za); cvt_3d(&b3, b, zb); while (a->next || b->next) { da = fabs(sa+a->len-sb); db = fabs(sb+b->len-sa); if ((a->next && da < db) || !b->next) { cvt_3d(&n, a->next, za); face(data, a3, n, b3); a3 = n; sa += a->len; a = a->next; } else { cvt_3d(&n, b->next, zb); face(data, b3, a3, n); b3 = n; sb += b->len; b = b->next; } } } void extrude(const struct path *path, const struct path *shape, double r, double d, void (*face)(void *data, struct point a, struct point b, struct point c), void *data) { const struct vertex *v, *next; /* current and next vertex */ struct path *prev, *curr; /* previous and current path */ struct path *tmp; if (!path->vertices || !path->vertices->next) return; v = shape->vertices; if (!v || !v->next) return; tmp = stretch_path(path, v->x, r); size(tmp); prev = round_path(tmp, r, d); free_path(tmp); size(prev); while (v->next) { next = v->next; tmp = stretch_path(path, next->x, r); size(tmp); curr = round_path(tmp, r, d); size(curr); free_path(tmp); mesh(prev, v->y, curr, next->y, face, data); free_path(prev); prev = curr; v = next; } free_path(prev); }