cae-tools/cameo/lang.y

594 lines
8.9 KiB
Plaintext

%{
/*
* lang.y - Toolpath adaptation language
*
* Written 2010-2013, 2015 by Werner Almesberger
* Copyright 2010-2013, 2015 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "path.h"
#include "ops.h"
#include "area.h"
#include "gnuplot.h"
#include "gerber.h"
#include "excellon.h"
#include "y.tab.h"
static double xo = 0, yo = 0, zo = 0; /* origin */
static double rot = 0;
static struct path *paths = NULL;
static struct path *remain = NULL;
#define MIL2MM(mil) ((mil)/1000*25.4)
static void add_paths(struct path *new)
{
struct path **anchor = &paths;
while (*anchor)
anchor = &(*anchor)->next;
*anchor = new;
}
static void translate(struct path *list, double x, double y, double z)
{
struct path *path;
struct point *p;
for (path = list; path; path = path->next)
for (p = path->first; p; p = p->next) {
p->x += x;
p->y += y;
p->z += z;
}
}
static void rotate(struct path *list, double angle)
{
double m[2][2], tmp;
struct point *p;
angle = angle/180.0*M_PI;
m[0][0] = cos(angle);
m[0][1] = -sin(angle);
m[1][0] = -m[0][1];
m[1][1] = m[0][0];
while (list) {
for (p = list->first; p; p = p->next) {
tmp = p->x*m[0][0]+p->y*m[0][1];
p->y = p->x*m[1][0]+p->y*m[1][1];
p->x = tmp;
}
list = list->next;
}
}
static void flip(struct path *list, enum axis axis, double center)
{
const struct path *path;
struct point *p;
for (path = list; path; path = path->next)
for (p = path->first; p; p = p->next) {
if (axis == axis_x)
p->x = 2*center-p->x;
else
p->y = 2*center-p->y;
}
}
static void flip_center(struct path *list, enum axis axis)
{
double min = 0, max = 0;
double coord;
const struct path *path;
const struct point *p;
int first = 1;
for (path = list; path; path = path->next)
for (p = path->first; p; p = p->next) {
coord = axis == axis_x ? p->x : p->y;
if (first || coord < min)
min = coord;
if (first || coord > max)
max = coord;
first = 0;
}
flip(list, axis, (min+max)/2);
}
static double ref_pick_1(int ref, double a, double b)
{
switch (ref) {
case 0:
return a;
case 1:
return (a+b)/2;
case 2:
return b;
default:
abort();
}
}
static void ref_pick_xy(int ref, double xa, double ya, double xb, double yb,
double *x, double *y)
{
*x = ref_pick_1((ref-1) % 3, xa, xb);
*y = ref_pick_1((ref-1)/3, ya, yb);
}
static void bbox(const struct path *path,
double *xa, double *ya, double *xb, double *yb)
{
const struct point *p;
int first = 1;
*xa = *ya = *xb = *yb = 0;
while (path) {
for (p = path->first; p; p = p->next) {
if (first || p->x < *xa)
*xa = p->x;
if (first || p->x > *xb)
*xb = p->x;
if (first || p->y < *ya)
*ya = p->y;
if (first || p->y > *yb)
*yb = p->y;
first = 0;
}
path = path->next;
}
}
static void align(int ref, double x, double y)
{
double xa = 0, ya = 0, xb = 0, yb = 0;
double xr, yr, xd, yd;
int first = 1;
bbox(paths, &xa, &ya, &xb, &yb);
ref_pick_xy(ref, xa, ya, xb, yb, &xr, &yr);
xd = x-xr;
yd = y-yr;
translate(paths, xd, yd, 0);
xo += xd;
yo += yd;
}
static void clear_paths(void)
{
struct path *next;
while (paths) {
next = paths->next;
path_free(paths);
paths = next;
}
}
static struct path **classify(struct path **anchor, struct path *path)
{
struct path **walk, *next;
if (!path)
return &(*anchor)->next;
for (walk = &paths; *walk; walk = &(*walk)->next);
*walk = path;
next = (*anchor)->next;
path_free(*anchor);
*anchor = next;
return anchor;
}
%}
%union {
double num;
char *str;
int flag;
enum {
OO_DOG = 1 << 0,
OO_INSIDE = 1 << 1,
} oopt;
enum axis {
axis_x,
axis_y
} axis;
};
%token TOK_ALIGN TOK_AREA TOK_ARRAY TOK_CLEAR TOK_DRILL TOK_EMPTY
%token TOK_FLIP TOK_KEEP TOK_MILL TOK_OFFSET TOK_OPTIMIZE
%token TOK_OUTSIDE TOK_PURGE TOK_REMAINDER
%token TOK_REMOVE TOK_RESET
%token TOK_REVERSE TOK_ROTATE TOK_STATS TOK_STL TOK_TRANSLATE
%token TOK_X TOK_Y TOK_Z
%token TOK_APPEND TOK_GERBER TOK_GNUPLOT TOK_EXCELLON TOK_WRITE
%token TOK_WRITE_GERBER
%token TOK_DOG TOK_INSIDE TOK_ANY
%token <num> NUM_EXP_MIL NUM_EXP_MM NUM_IMP_MIL NUM_IMP_MM REF
%token <str> STRING
%type <str> opt_filename
%type <num> dimen number opt_dimen x_size y_size
%type <flag> opt_any
%type <oopt> offset_options offset_option
%type <axis> axis
%%
all:
| command all
;
command:
TOK_ALIGN REF dimen dimen
{
align((int) $2, $3, $4);
}
| TOK_ALIGN REF dimen dimen dimen dimen
{
int ref = $2;
double x, y;
if ($3 > $5)
yyerror("left edge > right edge");
if ($4 > $6)
yyerror("bottom > top");
ref_pick_xy(ref, $3, $4, $5, $6, &x, &y);
align(ref, x, y);
}
| TOK_ARRAY x_size y_size number number
{
double x = $2*$4;
double y = $3*$5;
translate(paths, x, y, 0);
xo += x;
yo += y;
}
| TOK_CLEAR
{
clear_paths();
}
| TOK_RESET
{
xo = yo = rot = 0;
}
| TOK_OFFSET offset_options
{
struct path *new;
new = tool_comp_paths(paths,
!!($2 & OO_DOG), !!($2 & OO_INSIDE));
clear_paths();
paths = new;
}
| TOK_OPTIMIZE
{
paths = optimize_paths(paths);
}
| TOK_OUTSIDE
{
struct path *a;
struct path *b;
for (a = paths; a; a = a->next) {
for (b = paths; b; b = b->next)
if (a != b && path_is_inside(a, b))
break;
if (!b)
a->outside = 1;
}
}
| TOK_REVERSE
{
struct path *tmp;
tmp = reverse_paths(paths);
clear_paths();
paths = tmp;
}
| TOK_ROTATE number
{
rotate(paths, $2);
rot += $2;
}
| TOK_FLIP axis
{
flip_center(paths, $2);
}
| TOK_FLIP axis dimen
{
flip(paths, $2, $3);
}
| TOK_STATS
{
path_stats(paths);
}
| TOK_TRANSLATE dimen dimen
{
translate(paths, $2, $3, 0);
xo += $2;
yo += $3;
}
| TOK_Z dimen
{
zo += $2;
}
| TOK_Z dimen dimen
{
zo += $3-$2;
}
| TOK_GERBER dimen opt_filename
{
struct path *new;
new = gerber_read($3, $2/2);
rotate(new, rot);
translate(new, xo, yo, 0);
add_paths(new);
}
| TOK_GNUPLOT dimen opt_filename
{
struct path *new;
new = gnuplot_read($3, $2/2);
rotate(new, rot);
translate(new, xo, yo, 0);
add_paths(new);
}
| TOK_EXCELLON opt_filename
{
struct path *new;
new = excellon_read($2);
rotate(new, rot);
translate(new, xo, yo, 0);
add_paths(new);
}
| TOK_WRITE opt_filename
{
translate(paths, 0, 0, zo);
gnuplot_write($2, paths);
translate(paths, 0, 0, -zo);
}
| TOK_WRITE_GERBER opt_filename
{
gerber_write($2, paths);
}
| TOK_APPEND opt_filename
{
translate(paths, 0, 0, zo);
gnuplot_append($2, paths);
translate(paths, 0, 0, -zo);
}
| TOK_DRILL dimen opt_comma dimen
{
struct path **walk;
remain = paths;
paths = NULL;
walk = &remain;
while (*walk)
walk =
classify(walk, try_drill(*walk, $2, $4));
}
| TOK_AREA dimen
{
struct path *tmp;
tmp = area(paths, $2);
clear_paths();
paths = tmp;
}
| TOK_STL opt_filename
{
stl($2, paths);
}
| TOK_MILL opt_any dimen dimen
{
struct path **walk;
remain = paths;
paths = NULL;
walk = &remain;
while (*walk)
walk = classify(walk,
try_mill(*walk, $3, $4, $2));
}
| TOK_REMAINDER
{
clear_paths();
paths = remain;
remain = NULL;
}
| TOK_EMPTY
{
if (paths)
yyerror("path list is not empty");
}
| TOK_KEEP dimen dimen dimen dimen
{
struct path *tmp;
tmp = select_paths(paths, $2, $3, $4, $5, 1);
clear_paths();
paths = tmp;
}
| TOK_REMOVE dimen dimen dimen dimen
{
struct path *tmp;
tmp = select_paths(paths, $2, $3, $4, $5, 0);
clear_paths();
paths = tmp;
}
| TOK_PURGE opt_dimen
{
struct path *tmp;
tmp = purge_paths(paths, $2);
clear_paths();
paths = tmp;
}
;
opt_filename:
{
$$ = NULL;
}
| STRING
{
$$ = $1;
}
;
dimen:
NUM_EXP_MM
{
$$ = $1;
}
| NUM_IMP_MM
{
$$ = $1;
}
| NUM_EXP_MIL
{
$$ = MIL2MM($1);
}
| NUM_IMP_MIL
{
$$ = MIL2MM($1);
}
;
opt_dimen:
{
$$ = 0;
}
| dimen
{
$$ = $1;
}
;
x_size:
dimen
{
$$ = $1;
}
| '+' dimen
{
double xa, ya, xb, yb;
bbox(paths, &xa, &ya, &xb, &yb);
$$ = xb-xa+$2;
}
;
y_size:
dimen
{
$$ = $1;
}
| '+' dimen
{
double xa, ya, xb, yb;
bbox(paths, &xa, &ya, &xb, &yb);
$$ = yb-ya+$2;
}
;
number:
NUM_IMP_MIL
{
$$ = $1;
}
| NUM_IMP_MM
{
$$ = $1;
}
;
offset_options:
{
$$ = 0;
}
| offset_option offset_options
{
$$ = $1 | $2;
}
;
offset_option:
TOK_DOG
{
$$ = OO_DOG;
}
| TOK_INSIDE
{
$$ = OO_INSIDE;
}
;
axis:
TOK_X
{
$$ = axis_x;
}
| TOK_Y
{
$$ = axis_y;
}
;
opt_comma:
| ','
;
opt_any:
{
$$ = 0;
}
| TOK_ANY
{
$$ = 1;
}
;