papercraft/corners.c

383 lines
7.9 KiB
C
Raw Normal View History

2015-02-14 23:32:58 +01:00
/** \file
* Generate an OpenSCAD with connectors for each face.
*
* This imports the original STL file and then slices the corners
* off from it.
* Options are inside only (with face flush on outside)
* or with a slot for the face (like a corner cap)
2015-02-14 23:32:58 +01:00
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
2015-02-14 23:32:58 +01:00
#include <math.h>
#include <err.h>
#include <assert.h>
#include "v3.h"
2015-02-14 23:59:08 +01:00
#include "stl_3d.h"
2015-02-14 23:32:58 +01:00
static v3_t avg_x, avg_y, avg_z;
static void
print_multmatrix(
const refframe_t * const ref,
const int transpose
)
{
printf("multmatrix(m=["
"[%f,%f,%f,0],"
"[%f,%f,%f,0],"
"[%f,%f,%f,0],"
"[ 0, 0, 0,1]])\n",
transpose ? ref->x.p[0] : ref->x.p[0],
transpose ? ref->x.p[1] : ref->y.p[0],
transpose ? ref->x.p[2] : ref->z.p[0],
transpose ? ref->y.p[0] : ref->x.p[1],
transpose ? ref->y.p[1] : ref->y.p[1],
transpose ? ref->y.p[2] : ref->z.p[1],
transpose ? ref->z.p[0] : ref->x.p[2],
transpose ? ref->z.p[1] : ref->y.p[2],
transpose ? ref->z.p[2] : ref->z.p[2]
);
}
2015-03-07 23:45:25 +01:00
2015-02-15 22:57:37 +01:00
static void
2015-05-03 21:12:32 +02:00
print_normal(
const v3_t * normal,
int flip
2015-05-03 21:12:32 +02:00
)
{
const float x = normal->p[0];
const float y = normal->p[1];
const float z = normal->p[2];
const double length = sqrt(x*x+y*y+z*z);
const double b = acos(z / length);
const double c = x == 0 ? sign(y)*90 : atan2(y,x);
if (flip)
{
printf("rotate([0,%f,0])", -b*180/M_PI);
printf("rotate([0,0,%f])", -c*180/M_PI);
} else {
printf("rotate([%f,%f,%f])\n", 0.0, b * 180 / M_PI, c * 180 / M_PI);
}
2015-05-03 21:12:32 +02:00
}
static void
find_normal(
2015-02-15 22:57:37 +01:00
const stl_3d_t * const stl,
const stl_vertex_t * const v,
2015-05-03 21:12:32 +02:00
const float inset_dist,
v3_t * const avg
2015-02-15 22:57:37 +01:00
)
{
2015-05-03 21:12:32 +02:00
int * const face_used
= calloc(sizeof(*face_used), stl->num_face);
2015-02-15 22:57:37 +01:00
// generate all of the coplanar polygons at this vertex
2015-05-03 21:12:32 +02:00
const stl_vertex_t ** const vertex_list
= calloc(sizeof(**vertex_list), stl->num_vertex);
2015-02-15 22:57:37 +01:00
for (int j = 0 ; j < v->num_face; j++)
{
// generate the polygon face for this vertex
const stl_face_t * const f = v->face[j];
if (face_used[f - stl->face])
continue;
//ref.origin.p[0] = 0;
//ref.origin.p[1] = 0;
//ref.origin.p[2] = 0;
2015-02-15 22:57:37 +01:00
const int start_vertex = v->face_num[j];
const int vertex_count = stl_trace_face(
stl,
f,
vertex_list,
face_used,
start_vertex
);
2015-05-03 21:12:32 +02:00
// find this vertex in the vertex list
// and compute the vector that subdivides the
// two outbound edges
for (int k = 0 ; k < vertex_count ; k++)
{
if (vertex_list[k] != v)
continue;
2015-02-15 22:57:37 +01:00
2015-05-03 21:12:32 +02:00
v3_t p1 = vertex_list[(k+vertex_count-1) % vertex_count]->p;
v3_t p2 = vertex_list[k % vertex_count]->p;
v3_t p3 = vertex_list[(k+1) % vertex_count]->p;
refframe_t ref;
refframe_init(
&ref,
p2,
p3,
p1
);
double x, y;
refframe_inset(&ref, inset_dist, &x, &y, p1, p2, p3);
v3_t hole = refframe_project(&ref, (v3_t){{x,y,0}});
//hole = refframe_project(&ref, (v3_t){{10,0,0}});
//hole.p[0] = 10*ref.x.p[0]; // + ref.origin.p[0];
//hole.p[1] = 10*ref.x.p[1]; // + ref.origin.p[1];
//hole.p[2] = 10*ref.x.p[2]; // + ref.origin.p[2];
fprintf(stderr, "**** %p [%f,%f]=>%f,%f,%f\n", v, x, y,
hole.p[0],
hole.p[1],
hole.p[2]
);
2015-05-03 23:46:51 +02:00
#if 0
printf("color(\"green\") translate([%f,%f,%f]) sphere(r=1);\n",
hole.p[0],
hole.p[1],
hole.p[2]
);
hole = refframe_project(&ref, (v3_t){10,0,0});
//v3_t hole = refframe_project(&ref, (v3_t){5,5,0});
printf("translate([%f,%f,%f]) sphere(r=1);\n",
hole.p[0],
hole.p[1],
hole.p[2]
);
/*
hole = refframe_project(&ref, (v3_t){0,10,0});
//v3_t hole = refframe_project(&ref, (v3_t){5,5,0});
printf("%%translate([%f,%f,%f]) sphere(r=1);\n",
hole.p[0],
hole.p[1],
hole.p[2]
);
*/
#endif
2015-05-03 23:46:51 +02:00
//*avg = v3_add(*avg, ref.z);
*avg = v3_add(*avg, v3_norm(v3_sub(ref.origin, hole)));
//*avg = v3_add(*avg, (v3_sub(hole, ref.origin)));
2015-05-03 21:12:32 +02:00
}
}
#if 0
2015-02-15 22:57:37 +01:00
// use the transpose of the rotation matrix,
// which will rotate from (x,y) to the correct
// orientation relative to this connector node.
print_multmatrix(&ref, 1);
printf("{\n");
2015-02-15 22:57:37 +01:00
// generate the polygon plane
if (thickness != 0)
{
2015-03-07 23:45:25 +01:00
printf("translate([0,0,%f]) linear_extrude(height=%f) polygon(points=[\n",
translate,
thickness
2015-02-15 22:57:37 +01:00
);
2015-03-07 23:45:25 +01:00
for(int k=0 ; k < vertex_count ; k++)
{
double x, y;
refframe_inset(&ref, inset_dist, &x, &y,
vertex_list[(k+0) % vertex_count]->p,
vertex_list[(k+1) % vertex_count]->p,
vertex_list[(k+2) % vertex_count]->p
);
printf("[%f,%f],", x, y);
}
printf("\n]);\n");
}
2015-02-15 22:57:37 +01:00
// generate the mounting holes/pins
if (hole_rad != 0)
2015-02-15 22:57:37 +01:00
{
2015-03-07 23:45:25 +01:00
for(int k=0 ; k < vertex_count ; k++)
{
double x, y;
refframe_inset(&ref, inset_dist+hole_dist, &x, &y,
vertex_list[(k+0) % vertex_count]->p,
vertex_list[(k+1) % vertex_count]->p,
vertex_list[(k+2) % vertex_count]->p
);
printf("translate([%f,%f,%f]) cylinder(r=%f,h=%f, $fs=1);\n",
x, y, -hole_height/2,
hole_rad,
hole_height
);
}
2015-02-15 22:57:37 +01:00
}
printf("}\n");
}
2015-05-03 21:12:32 +02:00
#endif
2015-02-15 22:57:37 +01:00
free(face_used);
free(vertex_list);
}
2015-02-14 23:32:58 +01:00
int
main(
int argc,
char ** argv
)
2015-02-14 23:32:58 +01:00
{
if (argc <= 1)
{
fprintf(stderr, "Usage: corners file.stl > file-corners.scad\n");
return -1;
}
const char * const stl_name = argv[1];
int fd = open(stl_name, O_RDONLY);
if (fd < 0)
{
perror(stl_name);
return -1;
}
stl_3d_t * const stl = stl_3d_parse(fd);
2015-02-14 23:59:08 +01:00
if (!stl)
2015-02-14 23:32:58 +01:00
return EXIT_FAILURE;
close(fd);
printf("module model() {\n"
"render() difference() {\n"
"import(\"%s\");\n",
stl_name
);
//printf("%%model();\n");
const double thickness = 3;
const double inset_dist = 5;
const double hole_dist = 5;
2015-05-05 02:31:32 +02:00
const double hole_rad = 1.5;
2015-02-14 23:32:58 +01:00
int * const face_used
= calloc(sizeof(*face_used), stl->num_face);
const stl_vertex_t ** const vertex_list
= calloc(sizeof(*vertex_list), stl->num_vertex);
2015-05-03 21:12:32 +02:00
// for face, generate the set of coplanar points that go with it
// and "drill" holes in the model for those corners.
for (int i = 0 ; i < stl->num_face ; i++)
{
if (face_used[i])
continue;
const stl_face_t * const f = &stl->face[i];
const int vertex_count = stl_trace_face(
stl,
f,
vertex_list,
face_used,
0
);
2015-02-15 20:55:43 +01:00
refframe_t ref;
refframe_init(
&ref,
f->vertex[0]->p,
f->vertex[1]->p,
f->vertex[2]->p
);
// replace the origin with the actual origin
//ref.origin.p[0] = 0;
//ref.origin.p[1] = 0;
//ref.origin.p[2] = 0;
printf("translate([%f,%f,%f])",
f->vertex[0]->p.p[0],
f->vertex[0]->p.p[1],
f->vertex[0]->p.p[2]
);
print_multmatrix(&ref, 0);
printf("{\n");
// generate a bolt hole for each non-copolanar corner
for (int j = 0 ; j < vertex_count ; j++)
{
double x, y;
refframe_inset(
&ref,
inset_dist,
&x,
&y,
vertex_list[(j+0) % vertex_count]->p,
vertex_list[(j+1) % vertex_count]->p,
vertex_list[(j+2) % vertex_count]->p
);
printf("translate([%f,%f,0]) cylinder(r=%f, h=%f, center=true);\n",
x,
y,
hole_rad,
10.0
);
}
printf("}\n");
}
printf("}\n}\n");
const int flip = 1;
if (!flip)
printf("model();\n");
2015-05-03 21:12:32 +02:00
// For each vertex, extract a small region around the corner
2015-05-03 23:46:51 +02:00
const int div = sqrt(stl->num_vertex);
const double spacing = 32;
for(int i = 0 ; i < stl->num_vertex ; i++)
2015-02-14 23:59:08 +01:00
{
const stl_vertex_t * const v = &stl->vertex[i];
2015-02-15 01:53:31 +01:00
const v3_t origin = v->p;
2015-02-14 23:32:58 +01:00
v3_t avg = {{ 0, 0, 0}};
2015-05-03 21:12:32 +02:00
find_normal(stl, v, inset_dist, &avg);
if (flip)
{
2015-05-03 23:46:51 +02:00
printf("translate([%f,%f,20])", (i/div)*spacing, (i%div)*spacing);
printf("render() intersection()");
}
2015-05-03 23:46:51 +02:00
printf("{\n");
2015-02-15 20:55:43 +01:00
2015-05-03 23:46:51 +02:00
//printf("%%\n");
if (flip)
{
print_normal(&avg, 1);
printf("translate([%f,%f,%f])",
-origin.p[0], -origin.p[1], -origin.p[2]);
printf("model();\n");
printf("translate([0,0,-20]) cylinder(r=15,h=20);\n");
} else {
printf("translate([%f,%f,%f])",
origin.p[0], origin.p[1], origin.p[2]);
print_normal(&avg, 0);
printf("%%translate([0,0,-20]) cylinder(r=15,h=20);\n");
}
2015-03-07 19:20:12 +01:00
2015-05-03 23:46:51 +02:00
//avg = v3_norm(avg);
2015-03-07 19:20:12 +01:00
printf("}\n");
2015-02-14 23:32:58 +01:00
}
return 0;
}