/* * 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 * - the rounding is only accurate for x = 0. For x > 0, we need to add * more points. Tricky. */ #include #include #include #include "path.h" #include "extrude.h" #define alloc_tn(t, n) ((t *) malloc(sizeof(t)*(n))) static void slice(double x, double y, double nx, double ny, const struct path *shape, struct point *p) { const struct vertex *v; for (v = shape->vertices; v; v = v->next) { p->x = x+nx*v->x; p->y = y+ny*v->x; p->z = v->y; p++; } } static void mesh(const struct point *a, const struct point *b, int n, void (*face)(void *data, struct point a, struct point b, struct point c), void *data) { int i; for (i = 0; i != n-1; i++) { face(data, a[i], b[i], a[i+1]); face(data, a[i+1], b[i], b[i+1]); } } void extrude(const struct path *path, const struct path *shape, void (*face)(void *data, struct point a, struct point b, struct point c), void *data) { const struct vertex *v; /* current vertex (for iteration) */ const struct vertex *a, *b, *c; /* previous, current, next vertex */ struct point *prev, *this; /* previous and current slice */ double nx, ny; /* 2D normals */ double f; /* factor for normalization */ double tx, ty; /* temporary 2D normals */ int n = 0; /* number of vertices in shape */ if (!path->vertices || !path->vertices->next || !shape->vertices) return; for (v = shape->vertices; v; v = v->next) n++; prev = alloc_tn(struct point, n); this = alloc_tn(struct point, n); a = path->vertices; b = a->next; nx = b->y-a->y; ny = a->x-b->x; f = hypot(nx, ny); slice(a->x, a->y, nx/f, ny/f, shape, prev); for (v = path->vertices->next; v->next; v = v->next) { b = v; c = v->next; tx = b->y-a->y; ty = a->x-b->x; f = hypot(tx, ty); nx = tx/f; ny = ty/f; tx = c->y-b->y; ty = b->x-c->x; f = hypot(tx, ty); nx += tx/f; ny += ty/f; slice(b->x, b->y, nx/2, ny/2, shape, this); mesh(prev, this, n, face, data); memcpy(prev, this, sizeof(*prev)*n); a = v; } nx = v->y-a->y; ny = a->x-v->x; f = hypot(nx, ny); slice(v->x, v->y, nx/f, ny/f, shape, this); mesh(prev, this, n, face, data); /* @@@ To do: close shape and close top and bottom */ free(prev); free(this); }