From 2bb95317408c25a34f7fc4a489008d112fe45669 Mon Sep 17 00:00:00 2001 From: Trammell Hudson Date: Thu, 11 Dec 2014 20:29:09 -0500 Subject: [PATCH] parse binary stl, merge vertices --- Bunny-LowPoly.stl | Bin 0 -> 14684 bytes unfold.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 Bunny-LowPoly.stl create mode 100644 unfold.c diff --git a/Bunny-LowPoly.stl b/Bunny-LowPoly.stl new file mode 100644 index 0000000000000000000000000000000000000000..94a9566c3c2422de4f4231750c12ff769d1ed86b GIT binary patch literal 14684 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 literal 0 HcmV?d00001 diff --git a/unfold.c b/unfold.c new file mode 100644 index 0000000..064891e --- /dev/null +++ b/unfold.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + + +#define EPS 0.0001 + +typedef struct +{ + char header[80]; + uint32_t num_triangles; +} __attribute__((__packed__)) +stl_header_t; + +typedef struct +{ + float p[3]; +} v3_t; + +typedef struct +{ + v3_t normal; + v3_t p0; + v3_t p1; + v3_t p2; +} __attribute__((__packed__)) +stl_face_t; + + +#define MAX_POINTS 24 + +typedef struct +{ + int n; + int p[MAX_POINTS]; +} poly_t; + + +static int +v3_eq( + const v3_t * v1, + const v3_t * v2 +) +{ + float dx = v1->p[0] - v2->p[0]; + float dy = v1->p[1] - v2->p[1]; + float dz = v1->p[2] - v2->p[2]; + + if (-EPS < dx && dx < EPS + && -EPS < dy && dy < EPS + && -EPS < dz && dz < EPS) + return 1; + + return 0; +} + + +int main(void) +{ + const size_t max_len = 1 << 20; + uint8_t * const buf = calloc(max_len, 1); + + ssize_t rc = read(0, buf, max_len); + if (rc == -1) + return EXIT_FAILURE; + + const stl_header_t * const hdr = (const void*) buf; + const stl_face_t * const faces = (const void*)(hdr+1); + const int num_triangles = hdr->num_triangles; + + fprintf(stderr, "header: '%s'\n", hdr->header); + fprintf(stderr, "num: %d\n", num_triangles); + + // worst case -- all separate polygons + poly_t * const polys = calloc(num_triangles, sizeof(*polys)); + + // Collapse coplanar triangles into larger polygons + v3_t * const vertices = calloc(num_triangles, 3); + int num_vertices = 0; + + for(int i = 0 ; i < num_triangles ; i++) + { + // see if this matches an existing vertex + const stl_face_t * const t = &faces[i]; + poly_t * const p = &polys[i]; + p->n = 3; + p->p[0] = p->p[1] = p->p[2] = -1; + + for (int j = 0 ; j < num_vertices ; j++) + { + const v3_t * const v = &vertices[j]; + if (p->p[0] == -1 && v3_eq(v, &t->p0)) + p->p[1] = j; + if (p->p[1] == -1 && v3_eq(v, &t->p1)) + p->p[1] = j; + if (p->p[2] == -1 && v3_eq(v, &t->p2)) + p->p[2] = j; + + // check if we've found all of them + if (p->p[0] >= 0 && p->p[1] >= 0 && p->p[2] >= 0) + break; + } + + // create new points if we haven't found matches + if (p->p[0] < 0) + { + p->p[0] = num_vertices; + vertices[num_vertices++] = t->p0; + } + if (p->p[1] < 0) + { + p->p[1] = num_vertices; + vertices[num_vertices++] = t->p1; + } + if (p->p[3] < 0) + { + p->p[3] = num_vertices; + vertices[num_vertices++] = t->p2; + } + } + + fprintf(stderr, "unique vertices: %d\n", num_vertices); + + return 0; +}