mirror of
git://projects.qi-hardware.com/cae-tools.git
synced 2024-12-23 08:39:33 +02:00
ptrude/: functions for path stretching and calculation of proportional length
This commit is contained in:
parent
c202eda676
commit
7ef626988c
140
ptrude/path.c
140
ptrude/path.c
@ -49,6 +49,7 @@ static struct vertex *alloc_vertex(void)
|
|||||||
v->d = 0;
|
v->d = 0;
|
||||||
v->tag = NULL;
|
v->tag = NULL;
|
||||||
v->next = NULL;
|
v->next = NULL;
|
||||||
|
v->len = 0;
|
||||||
return v;
|
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)
|
double r, double d, const char *tag)
|
||||||
{
|
{
|
||||||
struct vertex *v;
|
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
|
* "corner" replaces a corner with a ploygon if the corner is too sharp to be
|
||||||
* be within distance "d" of the bend radius. This may change the point from
|
* within distance "d" of the bend radius. This may change the point from
|
||||||
* where we resume drawing (originally the corner point, "b"). "corner"
|
* where we resume drawing (originally the corner point, "b"). "corner"
|
||||||
* therefore returns the new end of the arc.
|
* 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)
|
const struct vertex *b, const struct vertex *c, double r, double d)
|
||||||
{
|
{
|
||||||
/* points to vectors */
|
/* 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 */
|
double x, y; /* current position; for iteration */
|
||||||
int i; /* segment; 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
|
* http://en.wikipedia.org/wiki/Dot_product
|
||||||
* dp = a*b*cos 2t
|
* 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 the corner is already smooth enough, we just keep what we have.
|
||||||
*/
|
*/
|
||||||
if (dd <= d) {
|
if (dd <= d) {
|
||||||
append_vertex(path, clone_vertex(b));
|
v1 = clone_vertex(b);
|
||||||
return b;
|
append_vertex(path, v1);
|
||||||
|
return v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 1: determine the total angle (2*t) */
|
/* 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;
|
f = s/aa;
|
||||||
x = b->x-f*ax;
|
x = b->x-f*ax;
|
||||||
y = b->y-f*ay;
|
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,
|
* 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;
|
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 *round_path(const struct path *path, double r, double d)
|
||||||
{
|
{
|
||||||
struct path *new;
|
struct path *new;
|
||||||
const struct vertex *prev, *v;
|
struct vertex *prev;
|
||||||
|
const struct vertex *v;
|
||||||
|
|
||||||
new = alloc_path();
|
new = alloc_path();
|
||||||
prev = path->vertices;
|
if (!path->vertices)
|
||||||
if (!prev)
|
|
||||||
return new;
|
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;
|
return new;
|
||||||
|
|
||||||
if (prev->r)
|
if (prev->r)
|
||||||
@ -320,7 +373,7 @@ struct path *round_path(const struct path *path, double r, double d)
|
|||||||
if (prev->d)
|
if (prev->d)
|
||||||
d = 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)
|
if (v->r)
|
||||||
r = v->r;
|
r = v->r;
|
||||||
if (v->d)
|
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 *load_path(FILE *file)
|
||||||
{
|
{
|
||||||
struct path *path;
|
struct path *path;
|
||||||
|
@ -22,6 +22,14 @@ struct vertex {
|
|||||||
double d; /* max. distance of corner from ideal arc; 0 = prev */
|
double d; /* max. distance of corner from ideal arc; 0 = prev */
|
||||||
const char *tag;
|
const char *tag;
|
||||||
struct vertex *next;
|
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 {
|
struct path {
|
||||||
@ -32,7 +40,9 @@ struct path {
|
|||||||
|
|
||||||
void free_path(struct path *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 *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);
|
struct path *load_path(FILE *file);
|
||||||
void save_path(FILE *file, const struct path *path);
|
void save_path(FILE *file, const struct path *path);
|
||||||
|
Loading…
Reference in New Issue
Block a user