started to split stl parser into file
This commit is contained in:
parent
e5a6c2ebe4
commit
a038abbce9
7
Makefile
7
Makefile
@ -4,14 +4,19 @@ CFLAGS = \
|
||||
-O3 \
|
||||
-W \
|
||||
-Wall \
|
||||
-Wp,-MMD,$(dir $@).$(notdir $@).d \
|
||||
-Wp,-MT,$@ \
|
||||
|
||||
LDLIBS = \
|
||||
-lm \
|
||||
|
||||
all: unfold wireframe
|
||||
all: unfold wireframe corners
|
||||
|
||||
unfold: unfold.o
|
||||
wireframe: wireframe.o
|
||||
corners: corners.o stl_3d.o
|
||||
|
||||
clean:
|
||||
$(RM) *.o
|
||||
|
||||
-include .*.o.d
|
||||
|
338
corners.c
Normal file
338
corners.c
Normal file
@ -0,0 +1,338 @@
|
||||
/** \file
|
||||
* Generate an OpenSCAD with connectors for each face.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include "v3.h"
|
||||
|
||||
static int debug = 0;
|
||||
static int draw_labels = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char header[80];
|
||||
uint32_t num_triangles;
|
||||
} __attribute__((__packed__))
|
||||
stl_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
v3_t normal;
|
||||
v3_t p[3];
|
||||
uint16_t attr;
|
||||
} __attribute__((__packed__))
|
||||
stl_face_t;
|
||||
|
||||
|
||||
#define MAX_VERTEX 64
|
||||
|
||||
typedef struct stl_vertex stl_vertex_t;
|
||||
|
||||
struct stl_vertex
|
||||
{
|
||||
v3_t p;
|
||||
int num_edges;
|
||||
stl_vertex_t * edges[MAX_VERTEX];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Returns 1 for ever edge in f1 that is shared with f2.
|
||||
*/
|
||||
int
|
||||
coplanar_check(
|
||||
const stl_face_t * const f1,
|
||||
const stl_face_t * const f2
|
||||
)
|
||||
{
|
||||
// Verify that there are three matching points
|
||||
int match[3] = {0,0,0};
|
||||
for (int i = 0 ; i < 3 ; i++)
|
||||
{
|
||||
for (int j = 0 ; j < 3 ; j++)
|
||||
if (v3_eq(&f1->p[i], &f2->p[j]))
|
||||
match[i] = 1;
|
||||
}
|
||||
|
||||
uint8_t mask = 0;
|
||||
|
||||
if (match[0] && match[1])
|
||||
mask = 1;
|
||||
if (match[1] && match[2])
|
||||
mask = 2;
|
||||
if (match[2] && match[0])
|
||||
mask = 4;
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "%p %p: %d %d %d\n",
|
||||
f1,
|
||||
f2,
|
||||
match[0], match[1], match[2]
|
||||
);
|
||||
|
||||
// otherwise they do not share enough points
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
// find the four distinct points
|
||||
v3_t x1 = f1->p[0];
|
||||
v3_t x2 = f1->p[1];
|
||||
v3_t x3 = f1->p[2];
|
||||
v3_t x4;
|
||||
|
||||
for (int i = 0 ; i < 3 ; i++)
|
||||
{
|
||||
x4 = f2->p[i];
|
||||
if (v3_eq(&x1, &x4))
|
||||
continue;
|
||||
if (v3_eq(&x2, &x4))
|
||||
continue;
|
||||
if (v3_eq(&x3, &x4))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// (x3-x1) . ((x2-x1) X (x4-x3)) == 0
|
||||
v3_t dx31 = v3_sub(x3, x1);
|
||||
v3_t dx21 = v3_sub(x2, x1);
|
||||
v3_t dx43 = v3_sub(x4, x3);
|
||||
v3_t cross = v3_cross(dx21, dx43);
|
||||
float dot = v3_dot(dx31, cross);
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "dot %f:\n %f,%f,%f\n %f,%f,%f\n %f,%f,%f\n %f,%f,%f\n",
|
||||
dot,
|
||||
x1.p[0], x1.p[1], x1.p[2],
|
||||
x2.p[0], x2.p[1], x2.p[2],
|
||||
x3.p[0], x3.p[1], x3.p[2],
|
||||
x4.p[0], x4.p[1], x4.p[2]
|
||||
);
|
||||
|
||||
int check = -EPS < dot && dot < +EPS;
|
||||
|
||||
// if the dot product is not close enough to zero, they
|
||||
// are not coplanar.
|
||||
if (!check)
|
||||
return 0;
|
||||
|
||||
// coplanar! return the shared edge mask
|
||||
return mask;
|
||||
#else
|
||||
// if the normals are close enough, then it is coplanner
|
||||
if (v3_eq(&f1->normal, &f2->normal))
|
||||
return mask;
|
||||
else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline float
|
||||
sign(
|
||||
const float x
|
||||
)
|
||||
{
|
||||
if (x < 0)
|
||||
return -1;
|
||||
if (x > 0)
|
||||
return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a vector to the list of edges if it is not already present
|
||||
* and if it is not coplanar with other ones.
|
||||
* Note that if it is coplanar, but "outside" the other edges then it
|
||||
* will replace the inside one.
|
||||
*/
|
||||
void
|
||||
stl_edge_insert(
|
||||
stl_vertex_t * const v1,
|
||||
stl_vertex_t * const v2
|
||||
)
|
||||
{
|
||||
for (int i = 0 ; i < v1->num_edges ; i++)
|
||||
{
|
||||
// if v2 already exists in the edges, discard it
|
||||
if (v1->edges[i] == v2)
|
||||
return;
|
||||
}
|
||||
|
||||
// if we reach this point, we need to insert the edge
|
||||
if (debug)
|
||||
fprintf(stderr, "%p: edge %d -> %p\n",
|
||||
v1,
|
||||
v1->num_edges,
|
||||
v2
|
||||
);
|
||||
v1->edges[v1->num_edges++] = v2;
|
||||
}
|
||||
|
||||
|
||||
/** Find or create a vertex */
|
||||
stl_vertex_t *
|
||||
stl_vertex_find(
|
||||
stl_vertex_t ** const vertices,
|
||||
int * num_vertex_ptr,
|
||||
const v3_t * const p
|
||||
)
|
||||
{
|
||||
const int num_vertex = *num_vertex_ptr;
|
||||
|
||||
for (int x = 0 ; x < num_vertex ; x++)
|
||||
{
|
||||
stl_vertex_t * const v = vertices[x];
|
||||
|
||||
if (v3_eq(&v->p, p))
|
||||
return v;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "%d: %f,%f,%f\n",
|
||||
num_vertex,
|
||||
p->p[0],
|
||||
p->p[1],
|
||||
p->p[2]
|
||||
);
|
||||
|
||||
stl_vertex_t * const v = vertices[(*num_vertex_ptr)++] = calloc(1, sizeof(*v));
|
||||
v->p = *p;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 stl_faces = (const void*)(hdr+1);
|
||||
const int num_triangles = hdr->num_triangles;
|
||||
const float thick = 7.8;
|
||||
const int do_square = 1;
|
||||
|
||||
fprintf(stderr, "header: '%s'\n", hdr->header);
|
||||
fprintf(stderr, "num: %d\n", num_triangles);
|
||||
|
||||
// generate the unique list of vertices and their
|
||||
// correponding edges
|
||||
stl_vertex_t ** const vertices = calloc(3*num_triangles, sizeof(*vertices));
|
||||
|
||||
int num_vertex = 0;
|
||||
|
||||
for(int i = 0 ; i < num_triangles ; i++)
|
||||
{
|
||||
if (debug) fprintf(stderr, "---------- triangle %d (%d)\n", i, num_vertex);
|
||||
|
||||
stl_vertex_t * vp[3] = {};
|
||||
|
||||
for (int j = 0 ; j < 3 ; j++)
|
||||
{
|
||||
const v3_t * const p = &stl_faces[i].p[j];
|
||||
vp[j] = stl_vertex_find(vertices, &num_vertex, p);
|
||||
}
|
||||
|
||||
// walk all of other triangles to figure out if
|
||||
// any of the triangles are coplanar and have shared
|
||||
// edges.
|
||||
|
||||
uint8_t coplanar_mask = 0;
|
||||
for (int j = 0 ; j < num_triangles ; j++)
|
||||
{
|
||||
if (j == i)
|
||||
continue;
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "%d: check %d -> %d\n", num_vertex, i, j);
|
||||
|
||||
coplanar_mask |= coplanar_check(
|
||||
&stl_faces[i], &stl_faces[j]);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "mask %d\n", coplanar_mask);
|
||||
|
||||
// all three vertices are mapped; generate the
|
||||
// connections
|
||||
for (int j = 0 ; j < 3 ; j++)
|
||||
{
|
||||
stl_vertex_t * const v = vp[j];
|
||||
|
||||
// if the edge from j to j+1 is not coplanar,
|
||||
// add it to the list
|
||||
if ((coplanar_mask & (1 << j)) == 0)
|
||||
{
|
||||
if (debug)
|
||||
fprintf(stderr, "%p: %d insert\n", v, j);
|
||||
stl_edge_insert(v, vp[(j+1) % 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%d unique vertices\n", num_vertex);
|
||||
printf("thick=%f;\n"
|
||||
"module connector(len) {\n"
|
||||
" render() difference() {\n"
|
||||
" cylinder(r=thick/2+2, h=2*thick);\n"
|
||||
//" translate([0,0,len/2+2]) cube([thick,thick,2*thick]);\n"
|
||||
" translate([0,0,thick/2+2]) cylinder(r=thick/2, h=2*thick);\n"
|
||||
" }\n"
|
||||
//" %%translate([0,0,len*0.48/2]) cube([thick,thick,len*0.48], center=true);\n"
|
||||
" %%translate([0,0,0]) cylinder(r=thick/2, h=len*0.48);\n"
|
||||
"}\n",
|
||||
thick
|
||||
);
|
||||
|
||||
for (int i = 0 ; i < num_vertex ; i++)
|
||||
{
|
||||
stl_vertex_t * const v = vertices[i];
|
||||
printf("translate([%f,%f,%f]) {\n",
|
||||
v->p.p[0],
|
||||
v->p.p[1],
|
||||
v->p.p[2]
|
||||
);
|
||||
|
||||
printf("sphere(r=%f); // %d %p\n", thick/2+2, i, v);
|
||||
|
||||
for (int j = 0 ; j < v->num_edges ; j++)
|
||||
{
|
||||
stl_vertex_t * const v2 = v->edges[j];
|
||||
const v3_t d = v3_sub(v2->p, v->p);
|
||||
const float len = v3_len(&v2->p, &v->p);
|
||||
|
||||
const float b = acos(d.p[2] / len) * 180/M_PI;
|
||||
const float c = d.p[0] == 0 ? sign(d.p[1]) * 90 : atan2(d.p[1], d.p[0]) * 180/M_PI;
|
||||
//
|
||||
printf("rotate([0,%f,%f]) ", b, c);
|
||||
|
||||
if (do_square)
|
||||
printf("connector(%f);\n", len);
|
||||
else
|
||||
printf(" cylinder(r=1, h=%f); // %p\n",
|
||||
len*.45,
|
||||
v2
|
||||
);
|
||||
}
|
||||
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
113
stl_3d.c
Normal file
113
stl_3d.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include "stl_3d.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static const int debug = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char header[80];
|
||||
uint32_t num_triangles;
|
||||
} __attribute__((__packed__))
|
||||
stl_3d_file_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
v3_t normal;
|
||||
v3_t p[3];
|
||||
uint16_t attr;
|
||||
} __attribute__((__packed__))
|
||||
stl_3d_file_triangle_t;
|
||||
|
||||
|
||||
/** Find or create a vertex */
|
||||
static stl_vertex_t *
|
||||
stl_vertex_find(
|
||||
stl_vertex_t * const vertices,
|
||||
int * num_vertex_ptr,
|
||||
const v3_t * const p
|
||||
)
|
||||
{
|
||||
const int num_vertex = *num_vertex_ptr;
|
||||
|
||||
for (int x = 0 ; x < num_vertex ; x++)
|
||||
{
|
||||
stl_vertex_t * const v = &vertices[x];
|
||||
|
||||
if (v3_eq(&v->p, p))
|
||||
return v;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf(stderr, "%d: %f,%f,%f\n",
|
||||
num_vertex,
|
||||
p->p[0],
|
||||
p->p[1],
|
||||
p->p[2]
|
||||
);
|
||||
|
||||
stl_vertex_t * const v = &vertices[(*num_vertex_ptr)++];
|
||||
v->p = *p;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
stl_3d_t *
|
||||
stl_3d_parse(
|
||||
int fd
|
||||
)
|
||||
{
|
||||
ssize_t rc;
|
||||
stl_3d_file_header_t hdr;
|
||||
|
||||
rc = read(fd, &hdr, sizeof(hdr));
|
||||
if (rc != sizeof(hdr))
|
||||
return NULL;
|
||||
|
||||
const int num_triangles = hdr.num_triangles;
|
||||
fprintf(stderr, "%d triangles\n", num_triangles);
|
||||
|
||||
stl_3d_file_triangle_t * fts;
|
||||
const size_t file_len = num_triangles * sizeof(*fts);
|
||||
fts = calloc(1, file_len);
|
||||
|
||||
rc = read(fd, &fts, file_len);
|
||||
if (rc < 0 || (size_t) rc != file_len)
|
||||
return NULL;
|
||||
|
||||
stl_3d_t * const stl = calloc(1, sizeof(*stl));
|
||||
|
||||
*stl = (stl_3d_t) {
|
||||
.num_vertex = 0,
|
||||
.num_face = num_triangles,
|
||||
.vertex = calloc(num_triangles, sizeof(*stl->vertex)),
|
||||
.face = calloc(num_triangles, sizeof(*stl->face)),
|
||||
};
|
||||
|
||||
for(int i = 0 ; i < num_triangles ; i++)
|
||||
{
|
||||
const stl_3d_file_triangle_t * const ft = &fts[i];
|
||||
stl_face_t * const f = &stl->face[i];
|
||||
|
||||
for (int j = 0 ; j < 3 ; j++)
|
||||
{
|
||||
const v3_t * const p = &ft->p[j];
|
||||
|
||||
stl_vertex_t * const v
|
||||
= stl_vertex_find(stl->vertex, &stl->num_vertex, p);
|
||||
|
||||
// add this vertex to this face
|
||||
f->vertex[j] = v;
|
||||
|
||||
// and add this face to the vertex
|
||||
v->face[v->num_face++] = f;
|
||||
}
|
||||
}
|
||||
|
||||
return stl;
|
||||
}
|
43
stl_3d.h
Normal file
43
stl_3d.h
Normal file
@ -0,0 +1,43 @@
|
||||
/** \file
|
||||
* STL file format.
|
||||
*
|
||||
* Parse an STL file into an easily traversed structure.
|
||||
*/
|
||||
#ifndef _stl3d_h_
|
||||
#define _stl3d_h_
|
||||
|
||||
#include "v3.h"
|
||||
|
||||
typedef struct stl_vertex stl_vertex_t;
|
||||
typedef struct stl_face stl_face_t;
|
||||
|
||||
#define STL_MAX_FACES 64
|
||||
|
||||
struct stl_vertex {
|
||||
v3_t p;
|
||||
int num_face;
|
||||
stl_face_t *face[STL_MAX_FACES];
|
||||
};
|
||||
|
||||
struct stl_face
|
||||
{
|
||||
stl_vertex_t * vertex[3];
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int num_vertex;
|
||||
stl_vertex_t * vertex;
|
||||
|
||||
int num_face;
|
||||
stl_face_t * face;
|
||||
} stl_3d_t;
|
||||
|
||||
|
||||
stl_3d_t *
|
||||
stl_3d_parse(
|
||||
int fd
|
||||
);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user