/* * stl.c - STL file reading * * Written 2014-2015 by Werner Almesberger * Copyright 2014-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. */ /* * Format description: * http://en.wikipedia.org/wiki/STL_%28file_format%29 */ #include #include #include #include #include #include #include "stl.h" #define MAX_LINE 100 enum state { s_init, s_facet, s_loop, s_vertices, s_endloop, s_endfacet, }; static void stl_load_binary(FILE *file, void (*facet)(struct v f[3])) { char discard[75]; size_t n; uint32_t nf; uint16_t attr; float tmp[4*3]; struct v f[3]; int i; n = fread(discard, 1, sizeof(discard), file); if (n != sizeof(discard)) { fprintf(stderr, "incomplete header\n"); exit(1); } n = fread(&nf, 1, sizeof(nf), file); if (n != sizeof(nf)) { fprintf(stderr, "no number of facets\n"); exit(1); } while (nf--) { n = fread(&tmp, 1, sizeof(tmp), file); if (n != sizeof(tmp)) { fprintf(stderr, "incomplete facet\n"); exit(1); } for (i = 0; i != 3; i++) { f[i].x = tmp[3 * i + 3]; f[i].y = tmp[3 * i + 4]; f[i].z = tmp[3 * i + 5]; } facet(f); n = fread(&attr, 1, sizeof(attr), file); if (n != sizeof(attr)) { fprintf(stderr, "no attribute count\n"); exit(1); } if (attr) { fprintf(stderr, "non-zero attribute count\n"); exit(1); } } } static void stl_load_text(FILE *file, void (*facet)(struct v f[3])) { char buf[MAX_LINE + 1]; enum state state = s_init; struct v f[3]; int num_v = 0; char *s, *e; int n = 0; int end, got; while (fgets(buf, sizeof(buf), file)) { n++; if (!(n & 1023)) fprintf(stderr, "%d\r", n); for (s = buf; *s && isspace(*s); s++); e = strchr(s, 0); while (e != s && isspace(e[-1])) e--; *e = 0; end = 0; switch (state) { case s_init: sscanf(s, " %*s%n", &end); state = s_facet; break; case s_facet: if (!strncmp(s, "endsolid", 8)) return; sscanf(s, "facet normal %*f %*f %*f%n", &end); state = s_loop; break; case s_loop: sscanf(s, "outer loop%n", &end); state = s_vertices; num_v = 0; break; case s_vertices: got = sscanf(s, "vertex %f %f %f%n", &f[num_v].x, &f[num_v].y, &f[num_v].z, &end); if (got < 3) break; if (++num_v == 3) { facet(f); state = s_endloop; } break; case s_endloop: sscanf(s, "endloop%n", &end); state = s_endfacet; break; case s_endfacet: sscanf(s, "endfacet%n", &end); state = s_facet; break; } if (end != e - s) { fprintf(stderr, "cannot parse line %d (%d %ld)\n", n, end, e - s); exit(1); } } fprintf(stderr, "incomplete STL file\n"); exit(1); } void stl_load_file(FILE *file, void (*facet)(struct v f[3])) { char buf[5]; size_t n; n = fread(buf, 1, sizeof(buf), file); if (n != sizeof(buf)) { fprintf(stderr, "file too short\n"); exit(1); } if (memcmp(buf, "solid", 5)) { stl_load_binary(file, facet); } else { stl_load_text(file, facet); } } void stl_load(const char *name, void (*facet)(struct v f[3])) { FILE *file; file = fopen(name, "r"); if (!file) { perror(name); exit(1); } stl_load_file(file, facet); fclose(file); }