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

cameo: an attempt at area fill (WIP)

This commit is contained in:
Werner Almesberger 2012-03-18 13:16:26 -03:00
parent 6271d5f721
commit 2530a11c80
6 changed files with 350 additions and 9 deletions

View File

@ -1,8 +1,8 @@
#
# Makefile - Makefile of cameo
#
# Written 2010 by Werner Almesberger
# Copyright 2010 by Werner Almesberger
# Written 2010, 2012 by Werner Almesberger
# Copyright 2010, 2012 by Werner Almesberger
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,7 +15,7 @@ PREFIX ?= /usr/local
SHELL=/bin/bash
MAIN=cameo
OBJS=cameo.o excellon.o gerber.o gnuplot.o ops.o path.o shape.o \
OBJS=cameo.o excellon.o area.o gerber.o gnuplot.o ops.o path.o shape.o \
lex.yy.o y.tab.o
CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \

View File

@ -206,7 +206,7 @@ Tool path optimization:
Try to reduce the movements made between paths by reordering the paths.
Note that this disturbs the order generated by "offset" and should thus
not be used on paths that to be executed in a specific sequence.
not be used on paths that are to be executed in a specific sequence.
Statistics:

308
cameo/area.c Normal file
View File

@ -0,0 +1,308 @@
/*
* area.c - Area fill
*
* Written 2012 by Werner Almesberger
* Copyright 2012 Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <stddef.h>
#include <math.h>
#include <assert.h>
#include "util.h"
#include "path.h"
#include "area.h"
#define EPSILON 0.0001
static int bbox(const struct path *path,
double *xa, double *ya, double *xb, double *yb)
{
const struct point *p = path->first;
if (!p)
return 0;
*xa = *xb = p->x;
*ya = *yb = p->y;
while (p) {
if (p->x < *xa)
*xa = p->x;
if (p->x > *xb)
*xb = p->x;
if (p->y < *ya)
*ya = p->y;
if (p->y > *yb)
*yb = p->y;
p = p->next;
}
return 1;
}
/*
* @@@ this is a bit too simple. E.g., it would report A as being inside B
* in this case:
*
* +---+
* +---+ | |
* | A | | |
* +---+ | |
* | B |
* +--------+ |
* | |
* +------------+
*/
static int is_inside(const struct path *a, const struct path *b)
{
double xa, ya, xb, yb;
const struct point *p;
if (!bbox(b, &xa, &ya, &xb, &yb))
return 0;
for (p = a->first; p; p = p->next)
if (p->x < xa || p->x > xb ||
p->y < ya || p->y > yb)
return 0;
return 1;
}
/*
* Solve
*
* 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
*
* which we the solve with Cramer's rule:
* http://en.wikipedia.org/wiki/Cramer's_rule
*/
static int intersect(double ax, double ay, double bx, double by,
double cx, double cy, double dx, double dy, double *na, double *nb)
{
double det;
det = dx*by-bx*dy;
if (fabs(det) < EPSILON)
return 0;
*na = (dx*(cy-ay)-dy*(cx-ax))/det;
*nb = (bx*(cy-ay)-by*(cx-ax))/det;
return 1;
}
/*
* Solve
*
* (ax+n*bx-cx)^2+(ay+n*by-cy)^2 = r^2 for n
*
* http://en.wikipedia.org/wiki/Quadratic_equation
*/
static int touch(double ax, double ay, double bx, double by,
double cx, double cy, double r, double *n)
{
double dx = cx-ax;
double dy = cy-ay;
double a = bx*bx+by*by;
double b = -2*bx*dx-2*by*dy;
double c = dx*dx+dy*dy-r*r;
double d, n0, n1;
d = b*b-4*a*c;
if (d < 0)
return 0;
d = sqrt(d);
n0 = (-b-d)/2/a;
n1 = (-b+d)/2/a;
if (n0 > 0) {
*n = n0;
return 1;
}
if (n1 > 0) {
*n = n1;
return 1;
}
return 0;
}
static int hit_segment(double fx, double fy, double tx, double ty,
const struct point *a, const struct point *b, double r, double *n)
{
double dx, dy, d;
double px, py;
double na, nb;
printf(" seg (%g,%g)+(%g,%g) -> (%g,%g)-(%g,%g)\n",
fx, fy, tx, ty, a->x, a->y, b->x, b->y);
tx -= fx;
ty -= fy;
dx = b->x-a->x;
dy = b->y-a->y;
d = hypot(dx, dy);
px = a->x-dy/d*r;
py = a->y+dx/d*r;
if (!intersect(fx, fy, tx, ty, px, py, dx, dy, &na, &nb))
return 0;
printf("\tna %g (%g) nb %g (%g)\n", na, fx+tx*na, nb, fx+tx*nb);
if (nb <= 0) {
if (!touch(fx, fy, tx, ty, a->x, a->y, r, &na))
return 0;
}
if (nb >= 1) {
if (!touch(fx, fy, tx, ty, b->x, b->y, r, &na))
return 0;
}
if (na <= 0 || na >= 1)
return 0;
*n = na;
return 1;
}
static int hit_path(double fx, double fy, double tx, double ty,
const struct path *path, int inside, double r, double *x)
{
const struct point *p;
int left;
double nx, tmp;
int found = 0;
left = path_tool_is_left(path);
if (inside)
left = !left;
for (p = path->first; p != path->last; p = p->next) {
if (hit_segment(fx, fy, tx, ty,
left ? p : p->next, left ? p->next : p, r, &tmp)) {
if (!found || nx > tmp)
nx = tmp;
found = 1;
}
}
if (found)
*x = fx+nx*(tx-fx);
return found;
}
static const struct path **subordinates(const struct path *paths,
const struct path *path)
{
const struct path **sub, **w, **a, **b;;
const struct path *p;
int n = 0;
for (p = paths; p; p = p->next)
n++;
sub = alloc_size(sizeof(struct path *)*n);
w = sub;
for (p = paths; p; p = p->next)
if (p != path && is_inside(p, path) && !is_inside(path, p))
*w++ = p;
*w = NULL;
for (a = sub; a != w; a++)
for (b = sub; b != w; b++)
if (a != b && is_inside(*a, *b)) {
*a = *w--;
*w = NULL;
a--;
break;
}
return sub;
}
static void do_line(const struct path *path, const struct path **sub,
double xa, double xb, double y, double r_tool, struct path **res)
{
const struct path *last = path;
const struct path **s;
struct path *new;
double x, next;
printf(" y=%g\n", y);
if (!hit_path(xa-3*r_tool, y, xb, y, last, 1, r_tool, &x))
return;
while (1) {
printf(" x=%g\n", x);
next = xb;
last = NULL;
if (hit_path(x, y, xb, y, path, 1, r_tool, &next))
last = path;
for (s = sub; *s; s++)
if (hit_path(x, y, next, y, *s, 0, r_tool, &next))
last = *s;
new = path_new(r_tool, "");
path_add(new, x, y, path->first->z);
path_add(new, next, y, path->first->z);
new->next = *res;
*res = new;
if (!last)
return;
if (!hit_path(next+EPSILON, y, xb, y, last, last == path,
r_tool, &x))
return;
}
}
static void fill_path(const struct path *paths, const struct path *path,
double r_tool, double overlap, struct path **res)
{
const struct path **sub, **s;
const struct path **sub2, **s2;
double xa, ya, xb, yb;
int n, i;
if (!bbox(path, &xa, &ya, &xb, &yb))
return;
sub = subordinates(paths, path);
xa += r_tool;
ya += r_tool;
xb -= r_tool;
yb -= r_tool;
n = ceil((yb-ya)/(2*r_tool-overlap));
printf("x[%g:%g] y[%g:%g] n=%d\n", xa, xb, ya, yb, n);
for (i = 0; i <= n; i++)
do_line(path, sub, xa, xb, ya+(yb-ya)*((double) i/n), r_tool,
res);
for (s = sub; *s; s++) {
sub2 = subordinates(paths, *s);
for (s2 = sub2; *s2; s2++)
fill_path(paths, *s2, r_tool, overlap, res);
free(sub2);
}
free(sub);
}
struct path *area(const struct path *path, double r_tool, double overlap)
{
struct path *res = NULL;
if (!path)
return NULL;
fill_path(path, path_find_leftmost(path), r_tool, overlap, &res);
return res;
}

23
cameo/area.h Normal file
View File

@ -0,0 +1,23 @@
/*
* area.h - Area fill
*
* Written 2012 by Werner Almesberger
* Copyright 2012 Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef AREA_H
#define AREA_H
#include "path.h"
struct path *area(const struct path *path, double r_tool, double overlap);
#endif /* !AREA_H */

View File

@ -2,8 +2,8 @@
/*
* lang.l - Toolpath adaptation language
*
* Written 2010-2011 by Werner Almesberger
* Copyright 2010-2011 by Werner Almesberger
* Written 2010-2012 by Werner Almesberger
* Copyright 2010-2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -44,6 +44,7 @@ NUM -?[0-9]+\.?[0-9]*
<INITIAL>clear return TOK_CLEAR;
<INITIAL>drill return TOK_DRILL;
<INITIAL>empty return TOK_EMPTY;
<INITIAL>area return TOK_AREA;
<INITIAL>mill return TOK_MILL;
<INITIAL>offset return TOK_OFFSET;
<INITIAL>optimize return TOK_OPTIMIZE;

View File

@ -2,8 +2,8 @@
/*
* lang.y - Toolpath adaptation language
*
* Written 2010-2011 by Werner Almesberger
* Copyright 2010-2011 by Werner Almesberger
* Written 2010-2012 by Werner Almesberger
* Copyright 2010-2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
#include "path.h"
#include "ops.h"
#include "area.h"
#include "gnuplot.h"
#include "gerber.h"
#include "excellon.h"
@ -186,7 +187,7 @@ static struct path **classify(struct path **anchor, struct path *path)
};
%token TOK_ALIGN TOK_ARRAY TOK_CLEAR TOK_DRILL TOK_EMPTY
%token TOK_ALIGN TOK_ARRAY TOK_CLEAR TOK_DRILL TOK_EMPTY TOK_AREA
%token TOK_MILL TOK_OFFSET TOK_OPTIMIZE TOK_REMAINDER TOK_RESET
%token TOK_ROTATE TOK_STATS TOK_TRANSLATE TOK_Z
%token TOK_APPEND TOK_GERBER TOK_GNUPLOT TOK_EXCELLON TOK_WRITE
@ -327,6 +328,14 @@ command:
walk =
classify(walk, try_drill(*walk, $2, $4));
}
| TOK_AREA dimen opt_comma dimen
{
struct path *tmp;
tmp = area(paths, $2/2, $4);
clear_paths();
paths = tmp;
}
| TOK_MILL opt_any dimen dimen
{
struct path **walk;