/* * slice.c - Generate slices * * Written 2015 by Werner Almesberger * Copyright 2015 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. */ #include #include #include #include "util.h" #include "stl.h" #include "slice.h" struct facet { struct v a, b, c; struct facet *next; }; struct z { float z; }; static GTree *tree; static struct facet *facets = NULL; /* ----- Bounding box ------------------------------------------------------ */ static bool first = 1; static float min_x, max_x, min_y, max_y; static void bbox(float x, float y) { if (first) { min_x = max_x = x; min_y = max_y = y; first = 0; } else { if (x < min_x) min_x = x; if (y < min_y) min_y = y; if (x > max_x) max_x = x; if (y > max_y) max_y = y; } } /* ----- Data collection --------------------------------------------------- */ static inline bool eq(float a, float b) { return fabsf(a - b) < 1e-5; } static void mark_z(float z) { struct z *e; e = g_tree_lookup(tree, &z); if (e) return; e = alloc_type(struct z); e->z = z; g_tree_insert(tree, &e->z, e); } static void add(const struct v *a, const struct v *b, const struct v *c) { float cross; struct facet *f; cross = (b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x); if (!eq(cross, 0)) { fprintf(stderr, "inclined facet\n\t%f %f %f\n\t%f %f %f\n\t%f %f %f\n", a->x, a->y, a->z, b->x, b->y, b->z, c->x, c->y, c->z); exit(1); } bbox(a->x, a->y); bbox(b->x, b->y); bbox(c->x, c->y); f = alloc_type(struct facet); f->a = *a; f->b = *b; f->c = *c; f->next = facets; facets = f; } void slice(struct v f[3]) { bool ab = eq(f[0].z, f[1].z); bool bc = eq(f[1].z, f[2].z); if (ab && bc) { mark_z(f[0].z); return; } add(f + 0, f + 1, f + 2); } /* ----- Insert intermediate layers ---------------------------------------- */ struct ctx { float z_step; bool first; float z0; /* only defined if !first */ bool more; /* returned due to having made changes */ }; static gboolean check_z(gpointer key, gpointer value, gpointer data) { const struct z *z = value; struct ctx *ctx = data; float d; int n, i; if (ctx->first) { ctx->first = 0; ctx->z0 = z->z; return 0; } d = z->z - ctx->z0; if (d <= ctx->z_step) { ctx->z0 = z->z; return 0; } n = (d / ctx->z_step) + 1; for (i = 1; i < n; i++) mark_z(ctx->z0 + d / n * i); ctx->more = 1; return 1; } void slice_intermediate(float z_step) { struct ctx ctx = { .z_step = z_step, }; do { ctx.first = 1; ctx.more = 0; g_tree_foreach(tree, check_z, &ctx); } while (ctx.more); } /* ----- Dumping ----------------------------------------------------------- */ static bool cut(const struct v *a, const struct v *b, float z, struct v *res) { float dx, dy, dz; float f; if (a->z > b->z) return cut(b, a, z, res); if (eq(a->z, b->z)) return 0; if (a->z > z || b->z < z || eq(b->z, z)) return 0; dx = b->x - a->x; dy = b->y - a->y; dz = b->z - a->z; f = (z - a->z) / dz; res->x = f * dx + a->x; res->y = f * dy + a->y; res->z = z; return 1; } static gboolean dump_layer(gpointer key, gpointer value, gpointer data) { const struct z *z = value; const struct facet *f; struct v p1, p2; for (f = facets; f; f = f->next) { if (cut(&f->a, &f->b, z->z, &p1)) { if (!cut(&f->a, &f->c, z->z, &p2) && !cut(&f->b, &f->c, z->z, &p2)) continue; } else if (!cut(&f->a, &f->c, z->z, &p1) || !cut(&f->b, &f->c, z->z, &p2)) { continue; } printf("%f %f %f\n%f %f %f\n\n\n", p1.x, p1.y, z->z, p2.x, p2.y, z->z); } return 0; } static gboolean dump_box(gpointer key, gpointer value, gpointer data) { const struct z *z = value; float box = *(float *) data; printf("%f %f %f\n%f %f %f\n%f %f %f\n%f %f %f\n%f %f %f\n\n\n", min_x - box, min_y - box, z->z, max_x + box, min_y - box, z->z, max_x + box, max_y + box, z->z, min_x - box, max_y + box, z->z, min_x - box, min_y - box, z->z); return 0; } void slice_dump(float box) { g_tree_foreach(tree, dump_layer, NULL); if (box && !first) g_tree_foreach(tree, dump_box, &box); } /* ----- Initialization ---------------------------------------------------- */ static gint comp(gconstpointer a, gconstpointer b) { const float *za = a; const float *zb = b; return eq(*za, *zb) ? 0 : *za < *zb ? -1 : 1; } void slice_init(void) { tree = g_tree_new(comp); }