1
0
mirror of git://projects.qi-hardware.com/cae-tools.git synced 2025-04-21 12:27:27 +03:00

cameo: consider inside/outside also when checking corner points

This commit is contained in:
Werner Almesberger
2012-03-20 20:07:29 -03:00
parent 7a61482a04
commit 340fb2cf8b
2 changed files with 187 additions and 16 deletions

View File

@@ -25,7 +25,7 @@
#include "area.h"
#define EPSILON 0.0001
#define EPSILON 1e-6
static int bbox(const struct path *path,
@@ -107,13 +107,14 @@ static int cramer2(double a, double b, double c, double d, double e, double f,
/*
* Solve
* ax+na*bx = cx+nb*dx
* ay+na*by = cy+nb*dy
*
* ax + na*bx = cx + nb*dx
* ay + na*by = cy + nb*dy
*
* which is
*
* na*bx + nb*-dx = cx-ax
* na*by + nb*-dy = cy-ay
* na*bx + nb*-dx = cx - ax
* na*by + nb*-dy = cy - ay
*/
static int intersect(double ax, double ay, double bx, double by,
@@ -123,6 +124,55 @@ static int intersect(double ax, double ay, double bx, double by,
}
/*
* See above.fig. The equation we solve is
*
* Q = A+u*(AM)
* Q = B+v*(BP)
*
* equals
*
* ax + u*(mx-ax) = bx + v*(px-bx)
* ay + u*(my-ay) = by + v*(py-by)
*
* equals
*
* u*(mx-ax) + v*(bx-px) = bx - ax
* u*(my-ay) + v*(by-py) = by - ay
*
* For BC, the equation becomes
*
* Q = C+u*(CM)
* Q = B+v*(BP)
*/
static int above(const struct point *a, const struct point *b,
const struct point *c, double px, double py)
{
double ab, bc;
double mx, my;
double u, v;
ab = hypot(a->x-b->x, a->y-b->y);
bc = hypot(b->x-c->x, b->y-c->y);
if (fabs(ab) < EPSILON || fabs(bc) < EPSILON)
return 0;
mx = b->x-(b->y-a->y)/ab-(c->y-b->y)/bc;
my = b->y+(b->x-a->x)/ab+(c->x-b->x)/bc;
if (cramer2(mx-a->x, b->x-px, my-a->y, b->y-py, b->x-a->x, b->y-a->y,
&u, &v))
if (u >= 0 && u <= 1 && v >= 0)
return 1;
if (cramer2(mx-c->x, b->x-px, my-c->y, b->y-py, b->x-c->x, b->y-c->y,
&u, &v))
if (u >= 0 && u <= 1 && v >= 0)
return 1;
return 0;
}
/*
* Solve
*
@@ -131,7 +181,7 @@ static int intersect(double ax, double ay, double bx, double by,
* http://en.wikipedia.org/wiki/Quadratic_equation
*/
static int touch(double ax, double ay, double bx, double by,
static int touch_solve(double ax, double ay, double bx, double by,
double cx, double cy, double r, int enter, double *n)
{
double dx = cx-ax;
@@ -153,9 +203,42 @@ static int touch(double ax, double ay, double bx, double by,
}
/*
* The points A, B, and C are (if the path is left-handed):
*
* - A: the beginning of the segment leading into the corner
* - B: the corner point
* - C: the beginning of the segment leading out of the corner
*
* If the path is right-handed, we swap A and C, making it left-handed.
*/
static int touch(double ax, double ay, double bx, double by,
const struct point *a, const struct point *b, const struct point *c,
double r, int enter, int left, double *n)
{
double px, py;
if (!touch_solve(ax, ay, bx, by, b->x, b->y, r, enter, n))
return 0;
px = ax+*n*bx;
py = ay+*n*by;
return above(a, b, c, px, py) == left;
}
/*
* Here, the points A, B, C, and D are:
*
* - A: before the beginning of the current segment
* - B: the beginning
* - C: the end
* - D: the next point beyond the end
*/
static int hit_segment(double fx, double fy, double tx, double ty,
const struct point *a, const struct point *b, double r, int enter,
int left, double *n)
const struct point *a, const struct point *b, const struct point *c,
const struct point *d, double r, int enter, int left, double *n)
{
double dx, dy, nx, ny, nn;
double px, py;
@@ -164,8 +247,8 @@ static int hit_segment(double fx, double fy, double tx, double ty,
tx -= fx;
ty -= fy;
dx = b->x-a->x;
dy = b->y-a->y;
dx = c->x-b->x;
dy = c->y-b->y;
if (left) {
nx = dx;
@@ -181,17 +264,17 @@ static int hit_segment(double fx, double fy, double tx, double ty,
nn = hypot(nx, ny);
px = a->x-ny/nn*r;
py = a->y+nx/nn*r;
px = b->x-ny/nn*r;
py = b->y+nx/nn*r;
if (!intersect(fx, fy, tx, ty, px, py, dx, dy, &na, &nb))
return 0;
if (nb <= 0) {
if (!touch(fx, fy, tx, ty, a->x, a->y, r, enter, &na))
if (!touch(fx, fy, tx, ty, a, b, c, r, enter, left, &na))
return 0;
}
if (nb >= 1) {
if (!touch(fx, fy, tx, ty, b->x, b->y, r, enter, &na))
if (!touch(fx, fy, tx, ty, b, c, d, r, enter, left, &na))
return 0;
}
if (na <= 0 || na >= 1)
@@ -204,21 +287,28 @@ static int hit_segment(double fx, double fy, double tx, double ty,
static int hit_path(double fx, double fy, double tx, double ty,
const struct path *path, int inside, int enter, double r, double *x)
{
const struct point *p;
const struct point *p, *last, *next2;
int left;
double nx, tmp;
int found = 0;
/*
* @@@ We don't wrap around the ends properly and create a zero-sized
* imaginary segment between path->first and path->last.
*/
left = path_tool_is_left(path);
if (inside)
left = !left;
last = path->last;
for (p = path->first; p != path->last; p = p->next) {
if (hit_segment(fx, fy, tx, ty, p, p->next,
next2 = p->next->next ? p->next->next : path->first;
if (hit_segment(fx, fy, tx, ty, last, p, p->next, next2,
r, enter, left, &tmp)) {
if (!found || nx > tmp)
nx = tmp;
found = 1;
}
last = p;
}
if (found)
*x = fx+nx*(tx-fx);