/* * 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 line { float ax, ay; float bx, by; float cz; struct line *next; }; struct z { float z; bool present; struct line *lines; }; static GTree *tree; /* ----- 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-6; } static struct z *get_z(float z) { struct z *base; base = g_tree_lookup(tree, &z); if (base) return base; base = alloc_type(struct z); base->z = z; base->present = 0; base->lines = NULL; g_tree_insert(tree, &base->z, base); return base; } static void mark_z(float z) { struct z *base; base = get_z(z); base->present = 1; } static void add(const struct v *a, const struct v *b, const struct v *c) { float cross; struct z *z; struct line *line; if (eq(a->x, b->x) && eq(a->y, b->y)) { fprintf(stderr, "zero point\n"); return; } if (c->z < a->z) return; 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); z = get_z(a->z); line = alloc_type(struct line); line->ax = a->x; line->ay = a->y; line->bx = b->x; line->by = b->y; line->cz = c->z; line->next = z->lines; z->lines = line; } void slice(struct v f[3]) { bool ab = eq(f[0].z, f[1].z); bool bc = eq(f[1].z, f[2].z); bool ac = eq(f[0].z, f[2].z); if (ab && bc) mark_z(f[0].z); else if (ab) add(f + 0, f + 1, f + 2); else if (bc) add(f + 1, f + 2, f + 0); else if (ac) add(f + 0, f + 2, f + 1); } /* ----- 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 (!z->present) return 0; 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 gboolean dump_layer(gpointer key, gpointer value, gpointer data) { const struct z *z0 = data; const struct z *z1 = value; const struct line *line; if (z0->z > z1->z) return 0; if (!z1->present) return 0; for (line = z0->lines; line; line = line->next) if (line->cz > z1->z) printf("%f %f %f\n%f %f %f\n\n\n", line->ax, line->ay, z1->z, line->bx, line->by, z1->z); return 0; } static gboolean dump_range(gpointer key, gpointer value, gpointer data) { const struct z *z = value; if (z->present) g_tree_foreach(tree, dump_layer, value); return 0; } static gboolean dump_box(gpointer key, gpointer value, gpointer data) { const struct z *z = value; float box = *(float *) data; if (!z->present) return 0; 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_range, 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); }