1
0
mirror of git://projects.qi-hardware.com/cae-tools.git synced 2024-12-22 23:43:00 +02:00

ptrude/: functions for path stretching and calculation of proportional length

This commit is contained in:
Werner Almesberger 2011-07-31 08:46:59 -03:00
parent c202eda676
commit 7ef626988c
2 changed files with 136 additions and 14 deletions

View File

@ -49,6 +49,7 @@ static struct vertex *alloc_vertex(void)
v->d = 0;
v->tag = NULL;
v->next = NULL;
v->len = 0;
return v;
}
@ -89,7 +90,7 @@ static void append_vertex(struct path *path, struct vertex *v)
}
static const struct vertex *add_vertex(struct path *path, double x, double y,
static struct vertex *add_vertex(struct path *path, double x, double y,
double r, double d, const char *tag)
{
struct vertex *v;
@ -105,14 +106,47 @@ static const struct vertex *add_vertex(struct path *path, double x, double y,
}
double path_set_length(struct path *path)
{
struct vertex *v;
double sum = 0;
if (!path->vertices)
return 0;
for (v = path->vertices; v->next; v = v->next) {
v->len = hypot(v->x-v->next->x, v->y-v->next->y);
sum += v->len;
}
v->len = 0;
return sum;
}
static void adjust_length(struct vertex *from, struct vertex *to, double len)
{
struct vertex *v;
double sum, f;
sum = 0;
for (v = from; v != to; v = v->next) {
v->len = hypot(v->x-v->next->x, v->y-v->next->y);
sum += v->len;
}
f = len/sum;
for (v = from; v != to; v = v->next)
v->len *= f;
}
/*
* "corner" replaces a corner with a ploygon if the corner is too sharp to
* be within distance "d" of the bend radius. This may change the point from
* "corner" replaces a corner with a ploygon if the corner is too sharp to be
* within distance "d" of the bend radius. This may change the point from
* where we resume drawing (originally the corner point, "b"). "corner"
* therefore returns the new end of the arc.
*/
static const struct vertex *corner(struct path *path, const struct vertex *a,
static struct vertex *corner(struct path *path, struct vertex *a,
const struct vertex *b, const struct vertex *c, double r, double d)
{
/* points to vectors */
@ -148,6 +182,10 @@ static const struct vertex *corner(struct path *path, const struct vertex *a,
double x, y; /* current position; for iteration */
int i; /* segment; for iteration */
struct vertex *v0; /* first vertex of arc */
struct vertex *v1; /* last vertex of arc */
/*
* http://en.wikipedia.org/wiki/Dot_product
* dp = a*b*cos 2t
@ -203,8 +241,9 @@ static const struct vertex *corner(struct path *path, const struct vertex *a,
* If the corner is already smooth enough, we just keep what we have.
*/
if (dd <= d) {
append_vertex(path, clone_vertex(b));
return b;
v1 = clone_vertex(b);
append_vertex(path, v1);
return v1;
}
/* Step 1: determine the total angle (2*t) */
@ -243,7 +282,8 @@ static const struct vertex *corner(struct path *path, const struct vertex *a,
f = s/aa;
x = b->x-f*ax;
y = b->y-f*ay;
add_vertex(path, x, y, b->r, b->d, b->tag);
v0 = add_vertex(path, x, y, b->r, b->d, b->tag);
a->len = a->len-s;
/*
* Step 5: determine if we need intermediate points. If yes, how many,
@ -298,21 +338,34 @@ static const struct vertex *corner(struct path *path, const struct vertex *a,
*/
f = s/bb;
return add_vertex(path, b->x+f*bx, b->y+f*by, 0, 0, NULL);
v1 = add_vertex(path, b->x+f*bx, b->y+f*by, 0, 0, NULL);
v1->len = b->len-s;
/*
* Step 7: adjust the nominal length of the segments
*/
adjust_length(v0, v1, 2*s);
return v1;
}
struct path *round_path(const struct path *path, double r, double d)
{
struct path *new;
const struct vertex *prev, *v;
struct vertex *prev;
const struct vertex *v;
new = alloc_path();
prev = path->vertices;
if (!prev)
if (!path->vertices)
return new;
append_vertex(new, clone_vertex(prev));
if (!prev->next)
prev = clone_vertex(path->vertices);
append_vertex(new, prev);
if (!path->vertices->next)
return new;
if (prev->r)
@ -320,7 +373,7 @@ struct path *round_path(const struct path *path, double r, double d)
if (prev->d)
d = prev->d;
for (v = prev->next; v->next; v = v->next) {
for (v = path->vertices->next; v->next; v = v->next) {
if (v->r)
r = v->r;
if (v->d)
@ -332,6 +385,65 @@ struct path *round_path(const struct path *path, double r, double d)
}
static void move_vertex(struct path *path, const struct vertex *v,
double nx, double ny, double d)
{
struct vertex *new;
new = clone_vertex(v);
new->x += nx*d;
new->y += ny*d;
append_vertex(path, new);
}
struct path *stretch_path(const struct path *path, double d)
{
struct path *new; /* new path */
const struct vertex *v; /* current vertex (for iteration) */
const struct vertex *a, *b, *c; /* previous, current, next vertex */
double nx, ny; /* 2D normals */
double f; /* factor for normalization */
double tx, ty; /* temporary 2D normals */
new = alloc_path();
a = path->vertices;
b = a->next;
nx = b->y-a->y;
ny = a->x-b->x;
f = hypot(nx, ny);
move_vertex(new, a, nx/f, ny/f, d);
for (v = path->vertices->next; v->next; v = v->next) {
b = v;
c = v->next;
tx = b->y-a->y;
ty = a->x-b->x;
f = hypot(tx, ty);
nx = tx/f;
ny = ty/f;
tx = c->y-b->y;
ty = b->x-c->x;
f = hypot(tx, ty);
nx += tx/f;
ny += ty/f;
move_vertex(new, b, nx/2, ny/2, d);
a = v;
}
nx = v->y-a->y;
ny = a->x-v->x;
f = hypot(nx, ny);
move_vertex(new, v, nx/f, ny/f, d);
return new;
}
struct path *load_path(FILE *file)
{
struct path *path;

View File

@ -22,6 +22,14 @@ struct vertex {
double d; /* max. distance of corner from ideal arc; 0 = prev */
const char *tag;
struct vertex *next;
/*
* "len" is set by path_set_len to the distance to the next vertex, or
* 0 if this is the last vertex in the path. round_path adjusts "len"
* such that it corresponds to the length of the same part of the
* original path.
*/
double len;
};
struct path {
@ -32,7 +40,9 @@ struct path {
void free_path(struct path *path);
double path_set_length(struct path *path);
struct path *round_path(const struct path *path, double r, double d);
struct path *stretch_path(const struct path *path, double d);
struct path *load_path(FILE *file);
void save_path(FILE *file, const struct path *path);