ptrude/: path extrusion, work in progress

This commit is contained in:
Werner Almesberger 2011-07-28 22:31:25 -03:00
parent 4ae218c6dc
commit d4c96f129d
8 changed files with 574 additions and 0 deletions

13
ptrude/Makefile Normal file
View File

@ -0,0 +1,13 @@
CFLAGS = -Wall -g
LDFLAGS = -lm
OBJS = ptrude.o path.o
.PHONY: clean try
ptrude: $(OBJS)
try: ptrude
./ptrude <try | tee out
clean:
rm -f $(OBJS)

24
ptrude/README Normal file
View File

@ -0,0 +1,24 @@
File format
-----------
#r=radius
minimum bend radius. Propagates to all subsequent points.
#delta=distance
maximum distance of line from curve. Propagates to all
subsequent points.
#tag=name
name point or shape. Gets passed through 2D->2D transform.
Affects only the next point.
x-coord y-coord
line endpoint
#r=, #delta=, and #tag= modify the next point, e.g.,
0 0
#r=2
#tag=foo
1 0
1 1
would set the bend radius at the corner (and the final point) to 2 mm
and the tag of the corner point to "foo".

68
ptrude/arc.fig Normal file
View File

@ -0,0 +1,68 @@
#FIG 3.2 Produced by xfig version 3.2.5b
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 3822.761 2922.761 3825 7425 7193 5908 8325 2925
5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 3821.168 2921.168 3825 7290 4883 7159 8190 2925
5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 3822.431 2923.366 3825 7560 4969 7416 8459 2948
5 1 0 1 0 0 50 -1 -1 4.000 0 1 0 0 8324.358 7425.641 8775 7425 8706 7186 8325 6975
5 1 0 1 0 0 50 -1 -1 4.000 0 0 0 0 3823.445 2923.445 5400 2925 5284 3517 3825 4500
1 3 0 0 0 0 50 -1 20 0.000 1 0.0000 4725 7065 45 45 4725 7065 4770 7065
1 3 0 0 0 0 50 -1 20 0.000 1 0.0000 7065 5625 45 45 7065 5625 7110 5625
1 3 0 0 0 0 50 -1 20 0.000 1 0.0000 4950 7020 45 45 4950 7020 4995 7020
1 3 0 0 0 0 50 -1 20 0.000 1 0.0000 7245 5400 45 45 7245 5400 7290 5400
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
900 7425 3825 7425
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
8325 2925 8325 1125
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
0 0 1.00 120.00 120.00
0 0 1.00 120.00 120.00
3870 2790 8235 2790
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
3825 7425 6390 6795 8235 4320
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3825 2925 8235 4320
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3825 2925 7290 5580
2 1 1 2 0 0 50 -1 -1 6.000 0 0 -1 0 0 2
8235 4320 8280 3690
2 1 0 1 0 0 50 -1 -1 4.000 0 0 -1 0 0 2
8325 2925 8325 7650
2 1 0 1 0 0 50 -1 -1 4.000 0 0 -1 0 0 2
3825 7425 9000 7425
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
9000 2925 3330 2925
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3825 2925 6390 6795
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3825 2475 3825 8100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3825 2925 4860 7155
4 1 0 50 -1 18 18 0.0000 4 150 105 6075 2655 r\001
4 1 0 50 -1 18 18 0.0000 4 210 180 3690 7380 d\001
4 1 0 50 -1 18 18 0.0000 4 210 180 3690 7695 d\001
4 1 0 50 -1 18 18 0.0000 4 150 105 3645 5490 r\001
4 1 0 50 -1 18 18 0.0000 4 210 375 4365 6390 r-d\001
4 1 0 50 -1 18 18 0.0000 4 210 450 5580 6300 r+d\001
4 1 0 50 -1 18 18 0.0000 4 210 375 6210 5175 r-d\001
4 1 0 50 -1 18 18 0.0000 4 210 450 6840 4230 r+d\001
4 1 0 50 -1 18 18 0.0000 4 150 165 4545 7695 u\001
4 1 0 50 -1 18 18 0.0000 4 150 135 5625 7425 v\001
4 1 0 50 -1 18 18 0.0000 4 150 135 7290 6390 v\001
4 1 0 50 -1 18 18 0.0000 4 150 135 8055 5220 v\001
4 0 0 50 -1 18 18 0.0000 4 150 855 8640 3690 ...+v+u\001
4 1 0 50 -1 18 18 0.0000 4 195 240 8505 7380 2t\001
4 0 0 50 -1 18 18 0.0000 4 270 2085 9405 7200 (r-d)^2+u^2=r^2\001
4 0 0 50 -1 18 18 0.0000 4 270 2610 9405 7650 (r-d)^2+v^2=(r+d)^2\001
4 0 0 50 -1 18 18 0.0000 4 270 1530 9405 8100 2t = 2p+n*q\001
4 0 0 50 -1 18 18 0.0000 4 210 915 4410 3105 ...+q+p\001
4 1 0 50 -1 18 18 0.0000 4 210 180 4950 3555 q\001
4 1 0 50 -1 18 18 0.0000 4 210 180 4635 3870 q\001
4 1 0 50 -1 18 18 0.0000 4 210 180 4320 4050 q\001
4 1 0 50 -1 18 18 0.0000 4 210 180 3960 4185 p\001

68
ptrude/corner.fig Normal file
View File

@ -0,0 +1,68 @@
#FIG 3.2 Produced by xfig version 3.2.5b
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
5 1 0 2 0 7 48 -1 -1 0.000 0 1 0 0 4494.036 1337.375 4500 9000 6203 8807 9909 6759
5 1 0 1 0 7 48 -1 -1 0.000 0 1 0 0 4499.660 1353.986 5220 3105 5552 2928 5818 2713
5 1 0 1 0 7 52 -1 -1 0.000 0 1 0 0 7651.482 8999.573 9000 9000 8926 8559 8604 8045
5 1 0 1 0 7 52 -1 -1 0.000 0 1 0 0 3374.893 7199.935 3915 7200 3838 6922 2993 6818
5 1 0 2 0 7 48 -1 -1 0.000 0 1 0 0 1798.655 6524.275 1800 7200 2162 7094 2277 6047
1 3 0 0 0 7 46 -1 0 0.000 1 0.0000 2250 6255 45 45 2250 6255 2295 6255
1 3 0 0 0 7 46 -1 0 0.000 1 0.0000 1935 7065 45 45 1935 7065 1980 7065
1 3 0 0 0 7 46 -1 0 0.000 1 0.0000 4680 8820 45 45 4680 8820 4725 8820
1 3 0 0 0 7 46 -1 0 0.000 1 0.0000 9630 6750 45 45 9630 6750 9675 6750
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
9900 6750 4050 900
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
1575 9000 7650 9000 13050 3600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
7650 9000 4185 585
2 1 0 1 0 7 52 -1 -1 0.000 0 0 -1 0 0 2
7650 9000 11025 9000
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
675 7200 3375 7200 1125 4950
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
1800 7200 1800 5850
2 1 0 1 0 7 52 -1 -1 0.000 0 0 -1 0 0 2
3375 7200 4050 7200
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
2250 6075 1350 6975
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3375 7200 1620 6435
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
0 0 1.00 120.00 120.00
0 0 1.00 120.00 120.00
4500 9135 7650 9135
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
0 0 1.00 90.00 90.00
0 0 1.00 90.00 90.00
1800 7335 3375 7335
2 1 0 0 0 7 46 -1 0 0.000 0 0 -1 1 1 2
0 0 1.00 90.00 90.00
0 0 1.00 90.00 90.00
4500 1350 4500 9000
2 1 0 0 0 7 46 -1 0 0.000 0 0 -1 1 1 2
0 0 1.00 90.00 90.00
0 0 1.00 90.00 90.00
7425 8415 7650 9000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4500 9000 4500 675
4 1 0 50 -1 18 18 0.0000 4 210 180 7650 8685 d\001
4 0 0 50 -1 18 18 0.0000 4 150 105 4320 5580 r\001
4 0 0 50 -1 18 18 0.0000 4 150 105 6030 5760 r\001
4 0 0 50 -1 18 18 0.0000 4 195 90 5130 2475 t\001
4 0 0 50 -1 18 18 0.0000 4 270 1830 7425 1125 cos t = r/(r+d)\001
4 1 0 50 -1 18 18 0.0000 4 150 165 5985 9405 s\001
4 0 0 50 -1 18 18 0.0000 4 210 1305 7425 1575 s = r*tan t\001
4 0 0 50 -1 18 18 0.0000 4 195 240 8325 8775 2t\001
4 0 0 48 -1 18 18 0.0000 4 195 240 3330 7020 2t\001
4 1 0 48 -1 18 18 0.0000 4 195 90 2115 6525 t\001
4 1 0 48 -1 18 18 0.0000 4 150 105 1665 7020 r\001
4 1 0 48 -1 18 18 0.0000 4 210 180 2520 7110 d\001
4 1 0 50 -1 18 18 0.0000 4 150 165 2610 7605 s\001
4 0 0 50 -1 18 18 0.0000 4 270 2310 7425 2025 r^2+s^2 = (r+d)^2\001

344
ptrude/path.c Normal file
View File

@ -0,0 +1,344 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "path.h"
#define alloc_type(t) ((t *) malloc(sizeof(t)))
#define stralloc(s) strdup(s)
static double deg(double rad)
{
return rad/M_PI*180.0;
}
static struct path *alloc_path(void)
{
struct path *path;
path = alloc_type(struct path);
path->vertices = NULL;
path->last = &path->vertices;
return path;
}
static struct vertex *alloc_vertex(void)
{
struct vertex *v;
v = alloc_type(struct vertex);
v->r = 0;
v->d = 0;
v->tag = NULL;
v->next = NULL;
return v;
}
static void free_vertex(struct vertex *v)
{
free(v);
}
void free_path(struct path *path)
{
struct vertex *v, *next;
for (v = path->vertices; v; v = next) {
next = v->next;
free_vertex(v);
}
free(path);
}
static struct vertex *clone_vertex(const struct vertex *v)
{
struct vertex *new;
new = alloc_type(struct vertex);
*new = *v;
new->next = NULL;
return new;
}
static void append_vertex(struct path *path, struct vertex *v)
{
*path->last = v;
path->last = &v->next;
}
static const struct vertex *add_vertex(struct path *path, double x, double y,
double r, double d, const char *tag)
{
struct vertex *v;
v = alloc_vertex();
v->x = x;
v->y = y;
v->r = r;
v->d = d;
v->tag = tag;
append_vertex(path, v);
return v;
}
static const struct vertex *corner(struct path *path, const struct vertex *a,
const struct vertex *b, const struct vertex *c, double r, double d)
{
double ax = b->x-a->x;
double ay = b->y-a->y;
double bx = c->x-b->x;
double by = c->y-b->y;
double aa = hypot(ax, ay);
double bb = hypot(bx, by);
double dp = ax*bx+ay*by; /* a * b = a*b*cos 2t */
double cp = ax*by-ay*bx; /* |a x b| = a*b*sin 2t */
double dd; /* "d" of the given vectors */
double tt, s;
double t2, p, q, ang;
double u, v;
double f, x, y;
int n, i;
/*
* http://en.wikipedia.org/wiki/Dot_product
* dp = a*b*cos 2t
*
* http://en.wikipedia.org/wiki/Cross_product
* cp = a*b*sin 2t
*
* http://en.wikipedia.org/wiki/Tangent_half-angle_formula
* tan t = sin 2t/(1+cos 2t)
*/
tt = cp/(aa*bb+dp);
/*
* From s = r*tan t
*/
s = fabs(r*tt);
/*
* From r^2+s^2 = (r+d)^2
*/
dd = hypot(r, s)-r;
fprintf(stderr, "a = (%g, %g)-(%g, %g) = (%g, %g); |a| = %g\n",
b->x, b->y, a->x, a->y, ax, ay, aa);
fprintf(stderr, "b = (%g, %g)-(%g, %g) = (%g, %g); |b| = %g\n",
c->x, c->y, b->x, b->y, bx, by, bb);
fprintf(stderr, "sin 2t = %g, cos 2t = %g, tan t = %g\n",
cp/aa/bb, dp/aa/bb, tt);
fprintf(stderr, "r = %g, d = %g, s = %g, dd = %g\n", r, d, s, dd);
/*
* We only know how to make a rounded corner if two vectors are
* involved. They therefore have to be long enough to accommodate the
* entire arc, from beginning to end. Furthermore, we split the
* available length in half, one for the inbound arc, the other for the
* outbound arc.
*/
if (aa/2 < s) {
fprintf(stderr, "first vector is too short (%g/2 < %g)\n",
aa, s);
exit(1);
}
if (bb/2 < s) {
fprintf(stderr, "second vector is too short (%g/2 < %g)\n",
bb, s);
exit(1);
}
/*
* If the corner is already smooth enough, we just keep what we have.
*/
if (dd <= d) {
append_vertex(path, clone_vertex(b));
return b;
}
/* Step 1: determine the total angle (2*t) */
t2 = acos(dp/aa/bb);
/*
* Step 2: determine the maximum angle of the first and last segment.
*
* We use
* r*cos p = r-d
* cos p = 1-d/r
*/
p = acos(1-d/r);
/*
* Step 3: determine the maximum angle of intermediate segments (if
* there are any).
*
* We use
* (r+d)*cos q = r-d
* cos q = r-q/(r+d)
*/
q = acos((r-d)/(r+d));
fprintf(stderr, "t2 = %g, p(max) = %g, q(max) = %g\n",
deg(t2), deg(p), deg(q));
/*
* Step 4: emit the starting point of the arc
*/
f = s/aa;
x = b->x-f*ax;
y = b->y-f*ay;
add_vertex(path, x, y, b->r, b->d, b->tag);
/*
* Step 5: determine if we need intermediate points. If yes, how many,
* and then proceed to add them.
*/
if (t2 > 2*p) {
n = (int) ceil((t2-2*(p+q))/(2*q));
/*
* @@@ We should evenly distribute the slack, but that seems
* difficult. For now, we just center the polygon.
*/
q = (t2/2-p)/(n+1);
double dir = copysign(1, cp);
#if 0
if (cp < 0) {
// t2 = -t2;
q = -q;
p = -p;
}
#endif
if (n)
ang = p+q;
else
ang = t2/2;
u = tan(p)*(r-d);
v = tan(q)*(r-d);
f = (u+v)/aa;
for (i = 0; i <= n; i++) {
x += f*ax*cos(ang-q)-dir*f*ay*sin(ang-q);
y += dir*f*ax*sin(ang-q)+f*ay*cos(ang-q);
fprintf(stderr, " %d/%d: %g %g @ %g\n", i, n,
x, y, deg(ang));
add_vertex(path, x, y, 0, 0, NULL);
ang += 2*q;
f = (2*v)/aa;
}
}
/*
* Step 6: emit the finishing point of the arc
*/
f = s/bb;
return add_vertex(path, b->x+f*bx, b->y+f*by, 0, 0, NULL);
}
struct path *round_path(const struct path *path, double r, double d)
{
struct path *new;
const struct vertex *prev, *v;
new = alloc_path();
prev = path->vertices;
if (!prev)
return new;
append_vertex(new, clone_vertex(prev));
if (!prev->next)
return new;
if (prev->r)
r = prev->r;
if (prev->d)
d = prev->d;
for (v = prev->next; v->next; v = v->next) {
if (v->r)
r = v->r;
if (v->d)
d = v->d;
prev = corner(new, prev, v, v->next, r, d);
}
append_vertex(new, clone_vertex(v));
return new;
}
struct path *load_path(FILE *file)
{
struct path *path;
char buf[1100]; /* plenty :) */
char buf2[sizeof(buf)];
char *s;
float x, y, tmp;
float r = 0, d = 0;
const char *tag = NULL;
path = alloc_path();
while (fgets(buf, sizeof(buf),file)) {
s = strchr(buf, '\n');
if (s)
*s = 0;
if (sscanf(buf, "#r=%f", &tmp) == 1) {
r = tmp;
continue;
}
if (sscanf(buf, "#delta=%f", &tmp) == 1) {
d = tmp;
continue;
}
if (sscanf(buf, "#tag=%s", buf2) == 1) {
tag = stralloc(buf2);
continue;
}
if (*buf == '#')
continue;
if (sscanf(buf, "%f %f", &x, &y) != 2) {
fprintf(stderr, "can't parse \"%s\"\n", buf);
exit(1);
}
add_vertex(path, x, y, r, d, tag);
r = 0;
d = 0;
tag = NULL;
}
return path;
}
void save_path(FILE *file, const struct path *path)
{
const struct vertex *v;
for (v = path->vertices; v; v = v->next) {
if (v->r)
fprintf(file, "#r=%f\n", v->r);
if (v->d)
fprintf(file, "#delta=%f\n", v->d);
if (v->tag)
fprintf(file, "#delta=%f\n", v->d);
fprintf(file, "%f %f\n", v->x, v->y);
}
}

28
ptrude/path.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef PATH_H
#define PATH_H
#include <stdio.h>
struct vertex {
double x, y;
double r; /* minimum bend radius; 0 = use previous value */
double d; /* max. distance of corner from ideal arc; 0 = prev */
const char *tag;
struct vertex *next;
};
struct path {
struct vertex *vertices;
struct vertex **last;
};
void free_path(struct path *path);
struct path *round_path(const struct path *path, double r, double d);
struct path *load_path(FILE *file);
void save_path(FILE *file, const struct path *path);
#endif /* !PATH_H */

15
ptrude/ptrude.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
#include "path.h"
int main(void)
{
const struct path *path;
path = load_path(stdin);
path = round_path(path, 1, 0.1);
save_path(stdout, path);
return 0;
}

14
ptrude/try Normal file
View File

@ -0,0 +1,14 @@
0 0
#r=10
#delta=0.01
100 0
100 100
200 100
100 200
0 200
100 100
0 100
0 50
100 50
150 0
100 0