Root/
1 | %{ |
2 | /* |
3 | * lang.y - Toolpath adaptation language |
4 | * |
5 | * Written 2010-2013, 2015 by Werner Almesberger |
6 | * Copyright 2010-2013, 2015 by Werner Almesberger |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. |
12 | */ |
13 | |
14 | |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <math.h> |
18 | |
19 | #include "path.h" |
20 | #include "ops.h" |
21 | #include "area.h" |
22 | #include "gnuplot.h" |
23 | #include "gerber.h" |
24 | #include "excellon.h" |
25 | |
26 | #include "y.tab.h" |
27 | |
28 | |
29 | static double xo = 0, yo = 0, zo = 0; /* origin */ |
30 | static double rot = 0; |
31 | static struct path *paths = NULL; |
32 | static struct path *remain = NULL; |
33 | |
34 | |
35 | #define MIL2MM(mil) ((mil)/1000*25.4) |
36 | |
37 | |
38 | static void add_paths(struct path *new) |
39 | { |
40 | struct path **anchor = &paths; |
41 | |
42 | while (*anchor) |
43 | anchor = &(*anchor)->next; |
44 | *anchor = new; |
45 | } |
46 | |
47 | |
48 | static void translate(struct path *list, double x, double y, double z) |
49 | { |
50 | struct path *path; |
51 | struct point *p; |
52 | |
53 | for (path = list; path; path = path->next) |
54 | for (p = path->first; p; p = p->next) { |
55 | p->x += x; |
56 | p->y += y; |
57 | p->z += z; |
58 | } |
59 | } |
60 | |
61 | |
62 | static void rotate(struct path *list, double angle) |
63 | { |
64 | double m[2][2], tmp; |
65 | struct point *p; |
66 | |
67 | angle = angle/180.0*M_PI; |
68 | m[0][0] = cos(angle); |
69 | m[0][1] = -sin(angle); |
70 | m[1][0] = -m[0][1]; |
71 | m[1][1] = m[0][0]; |
72 | while (list) { |
73 | for (p = list->first; p; p = p->next) { |
74 | tmp = p->x*m[0][0]+p->y*m[0][1]; |
75 | p->y = p->x*m[1][0]+p->y*m[1][1]; |
76 | p->x = tmp; |
77 | } |
78 | list = list->next; |
79 | } |
80 | } |
81 | |
82 | |
83 | static void flip(struct path *list, enum axis axis, double center) |
84 | { |
85 | const struct path *path; |
86 | struct point *p; |
87 | |
88 | for (path = list; path; path = path->next) |
89 | for (p = path->first; p; p = p->next) { |
90 | if (axis == axis_x) |
91 | p->x = 2*center-p->x; |
92 | else |
93 | p->y = 2*center-p->y; |
94 | } |
95 | } |
96 | |
97 | |
98 | |
99 | static void flip_center(struct path *list, enum axis axis) |
100 | { |
101 | double min = 0, max = 0; |
102 | double coord; |
103 | const struct path *path; |
104 | const struct point *p; |
105 | int first = 1; |
106 | |
107 | for (path = list; path; path = path->next) |
108 | for (p = path->first; p; p = p->next) { |
109 | coord = axis == axis_x ? p->x : p->y; |
110 | if (first || coord < min) |
111 | min = coord; |
112 | if (first || coord > max) |
113 | max = coord; |
114 | first = 0; |
115 | } |
116 | flip(list, axis, (min+max)/2); |
117 | } |
118 | |
119 | |
120 | static double ref_pick_1(int ref, double a, double b) |
121 | { |
122 | switch (ref) { |
123 | case 0: |
124 | return a; |
125 | case 1: |
126 | return (a+b)/2; |
127 | case 2: |
128 | return b; |
129 | default: |
130 | abort(); |
131 | } |
132 | } |
133 | |
134 | |
135 | static void ref_pick_xy(int ref, double xa, double ya, double xb, double yb, |
136 | double *x, double *y) |
137 | { |
138 | *x = ref_pick_1((ref-1) % 3, xa, xb); |
139 | *y = ref_pick_1((ref-1)/3, ya, yb); |
140 | } |
141 | |
142 | |
143 | static void bbox(const struct path *path, |
144 | double *xa, double *ya, double *xb, double *yb) |
145 | { |
146 | const struct point *p; |
147 | int first = 1; |
148 | |
149 | *xa = *ya = *xb = *yb = 0; |
150 | |
151 | while (path) { |
152 | for (p = path->first; p; p = p->next) { |
153 | if (first || p->x < *xa) |
154 | *xa = p->x; |
155 | if (first || p->x > *xb) |
156 | *xb = p->x; |
157 | if (first || p->y < *ya) |
158 | *ya = p->y; |
159 | if (first || p->y > *yb) |
160 | *yb = p->y; |
161 | first = 0; |
162 | } |
163 | path = path->next; |
164 | } |
165 | } |
166 | |
167 | |
168 | static void align(int ref, double x, double y) |
169 | { |
170 | double xa = 0, ya = 0, xb = 0, yb = 0; |
171 | double xr, yr, xd, yd; |
172 | int first = 1; |
173 | |
174 | bbox(paths, &xa, &ya, &xb, &yb); |
175 | |
176 | ref_pick_xy(ref, xa, ya, xb, yb, &xr, &yr); |
177 | xd = x-xr; |
178 | yd = y-yr; |
179 | |
180 | translate(paths, xd, yd, 0); |
181 | xo += xd; |
182 | yo += yd; |
183 | } |
184 | |
185 | |
186 | static void clear_paths(void) |
187 | { |
188 | struct path *next; |
189 | |
190 | while (paths) { |
191 | next = paths->next; |
192 | path_free(paths); |
193 | paths = next; |
194 | } |
195 | } |
196 | |
197 | |
198 | static struct path **classify(struct path **anchor, struct path *path) |
199 | { |
200 | struct path **walk, *next; |
201 | |
202 | if (!path) |
203 | return &(*anchor)->next; |
204 | for (walk = &paths; *walk; walk = &(*walk)->next); |
205 | *walk = path; |
206 | next = (*anchor)->next; |
207 | path_free(*anchor); |
208 | *anchor = next; |
209 | return anchor; |
210 | } |
211 | |
212 | |
213 | %} |
214 | |
215 | |
216 | %union { |
217 | double num; |
218 | char *str; |
219 | int flag; |
220 | enum { |
221 | OO_DOG = 1 << 0, |
222 | OO_INSIDE = 1 << 1, |
223 | } oopt; |
224 | enum axis { |
225 | axis_x, |
226 | axis_y |
227 | } axis; |
228 | }; |
229 | |
230 | |
231 | %token TOK_ALIGN TOK_AREA TOK_ARRAY TOK_CLEAR TOK_DRILL TOK_EMPTY |
232 | %token TOK_FLIP TOK_KEEP TOK_MILL TOK_OFFSET TOK_OPTIMIZE |
233 | %token TOK_OUTSIDE TOK_PURGE TOK_REMAINDER |
234 | %token TOK_REMOVE TOK_RESET |
235 | %token TOK_REVERSE TOK_ROTATE TOK_STATS TOK_STL TOK_TRANSLATE |
236 | %token TOK_X TOK_Y TOK_Z |
237 | %token TOK_APPEND TOK_GERBER TOK_GNUPLOT TOK_EXCELLON TOK_WRITE |
238 | %token TOK_WRITE_GERBER |
239 | %token TOK_DOG TOK_INSIDE TOK_ANY |
240 | |
241 | %token <num> NUM_EXP_MIL NUM_EXP_MM NUM_IMP_MIL NUM_IMP_MM REF |
242 | %token <str> STRING |
243 | |
244 | %type <str> opt_filename |
245 | %type <num> dimen number opt_dimen x_size y_size |
246 | %type <flag> opt_any |
247 | %type <oopt> offset_options offset_option |
248 | %type <axis> axis |
249 | |
250 | %% |
251 | |
252 | all: |
253 | | command all |
254 | ; |
255 | |
256 | command: |
257 | TOK_ALIGN REF dimen dimen |
258 | { |
259 | align((int) $2, $3, $4); |
260 | } |
261 | | TOK_ALIGN REF dimen dimen dimen dimen |
262 | { |
263 | int ref = $2; |
264 | double x, y; |
265 | |
266 | if ($3 > $5) |
267 | yyerror("left edge > right edge"); |
268 | if ($4 > $6) |
269 | yyerror("bottom > top"); |
270 | |
271 | ref_pick_xy(ref, $3, $4, $5, $6, &x, &y); |
272 | align(ref, x, y); |
273 | } |
274 | | TOK_ARRAY x_size y_size number number |
275 | { |
276 | double x = $2*$4; |
277 | double y = $3*$5; |
278 | |
279 | translate(paths, x, y, 0); |
280 | xo += x; |
281 | yo += y; |
282 | } |
283 | | TOK_CLEAR |
284 | { |
285 | clear_paths(); |
286 | } |
287 | | TOK_RESET |
288 | { |
289 | xo = yo = rot = 0; |
290 | } |
291 | | TOK_OFFSET offset_options |
292 | { |
293 | struct path *new; |
294 | |
295 | new = tool_comp_paths(paths, |
296 | !!($2 & OO_DOG), !!($2 & OO_INSIDE)); |
297 | clear_paths(); |
298 | paths = new; |
299 | } |
300 | | TOK_OPTIMIZE |
301 | { |
302 | paths = optimize_paths(paths); |
303 | } |
304 | | TOK_OUTSIDE |
305 | { |
306 | struct path *a; |
307 | struct path *b; |
308 | |
309 | for (a = paths; a; a = a->next) { |
310 | for (b = paths; b; b = b->next) |
311 | if (a != b && path_is_inside(a, b)) |
312 | break; |
313 | if (!b) |
314 | a->outside = 1; |
315 | } |
316 | } |
317 | | TOK_REVERSE |
318 | { |
319 | struct path *tmp; |
320 | |
321 | tmp = reverse_paths(paths); |
322 | clear_paths(); |
323 | paths = tmp; |
324 | } |
325 | | TOK_ROTATE number |
326 | { |
327 | rotate(paths, $2); |
328 | rot += $2; |
329 | } |
330 | | TOK_FLIP axis |
331 | { |
332 | flip_center(paths, $2); |
333 | } |
334 | | TOK_FLIP axis dimen |
335 | { |
336 | flip(paths, $2, $3); |
337 | } |
338 | | TOK_STATS |
339 | { |
340 | path_stats(paths); |
341 | } |
342 | | TOK_TRANSLATE dimen dimen |
343 | { |
344 | translate(paths, $2, $3, 0); |
345 | xo += $2; |
346 | yo += $3; |
347 | } |
348 | | TOK_Z dimen |
349 | { |
350 | zo += $2; |
351 | } |
352 | | TOK_Z dimen dimen |
353 | { |
354 | zo += $3-$2; |
355 | } |
356 | | TOK_GERBER dimen opt_filename |
357 | { |
358 | struct path *new; |
359 | |
360 | new = gerber_read($3, $2/2); |
361 | rotate(new, rot); |
362 | translate(new, xo, yo, 0); |
363 | add_paths(new); |
364 | } |
365 | | TOK_GNUPLOT dimen opt_filename |
366 | { |
367 | struct path *new; |
368 | |
369 | new = gnuplot_read($3, $2/2); |
370 | rotate(new, rot); |
371 | translate(new, xo, yo, 0); |
372 | add_paths(new); |
373 | } |
374 | | TOK_EXCELLON opt_filename |
375 | { |
376 | struct path *new; |
377 | |
378 | new = excellon_read($2); |
379 | rotate(new, rot); |
380 | translate(new, xo, yo, 0); |
381 | add_paths(new); |
382 | } |
383 | | TOK_WRITE opt_filename |
384 | { |
385 | translate(paths, 0, 0, zo); |
386 | gnuplot_write($2, paths); |
387 | translate(paths, 0, 0, -zo); |
388 | } |
389 | | TOK_WRITE_GERBER opt_filename |
390 | { |
391 | gerber_write($2, paths); |
392 | } |
393 | | TOK_APPEND opt_filename |
394 | { |
395 | translate(paths, 0, 0, zo); |
396 | gnuplot_append($2, paths); |
397 | translate(paths, 0, 0, -zo); |
398 | } |
399 | | TOK_DRILL dimen opt_comma dimen |
400 | { |
401 | struct path **walk; |
402 | |
403 | remain = paths; |
404 | paths = NULL; |
405 | walk = &remain; |
406 | while (*walk) |
407 | walk = |
408 | classify(walk, try_drill(*walk, $2, $4)); |
409 | } |
410 | | TOK_AREA dimen |
411 | { |
412 | struct path *tmp; |
413 | |
414 | tmp = area(paths, $2); |
415 | clear_paths(); |
416 | paths = tmp; |
417 | } |
418 | | TOK_STL opt_filename |
419 | { |
420 | stl($2, paths); |
421 | } |
422 | | TOK_MILL opt_any dimen dimen |
423 | { |
424 | struct path **walk; |
425 | |
426 | remain = paths; |
427 | paths = NULL; |
428 | walk = &remain; |
429 | while (*walk) |
430 | walk = classify(walk, |
431 | try_mill(*walk, $3, $4, $2)); |
432 | } |
433 | | TOK_REMAINDER |
434 | { |
435 | clear_paths(); |
436 | paths = remain; |
437 | remain = NULL; |
438 | } |
439 | | TOK_EMPTY |
440 | { |
441 | if (paths) |
442 | yyerror("path list is not empty"); |
443 | } |
444 | | TOK_KEEP dimen dimen dimen dimen |
445 | { |
446 | struct path *tmp; |
447 | |
448 | tmp = select_paths(paths, $2, $3, $4, $5, 1); |
449 | clear_paths(); |
450 | paths = tmp; |
451 | } |
452 | | TOK_REMOVE dimen dimen dimen dimen |
453 | { |
454 | struct path *tmp; |
455 | |
456 | tmp = select_paths(paths, $2, $3, $4, $5, 0); |
457 | clear_paths(); |
458 | paths = tmp; |
459 | } |
460 | | TOK_PURGE opt_dimen |
461 | { |
462 | struct path *tmp; |
463 | |
464 | tmp = purge_paths(paths, $2); |
465 | clear_paths(); |
466 | paths = tmp; |
467 | } |
468 | ; |
469 | |
470 | opt_filename: |
471 | { |
472 | $$ = NULL; |
473 | } |
474 | | STRING |
475 | { |
476 | $$ = $1; |
477 | } |
478 | ; |
479 | |
480 | dimen: |
481 | NUM_EXP_MM |
482 | { |
483 | $$ = $1; |
484 | } |
485 | | NUM_IMP_MM |
486 | { |
487 | $$ = $1; |
488 | } |
489 | | NUM_EXP_MIL |
490 | { |
491 | $$ = MIL2MM($1); |
492 | } |
493 | | NUM_IMP_MIL |
494 | { |
495 | $$ = MIL2MM($1); |
496 | } |
497 | ; |
498 | |
499 | opt_dimen: |
500 | { |
501 | $$ = 0; |
502 | } |
503 | | dimen |
504 | { |
505 | $$ = $1; |
506 | } |
507 | ; |
508 | |
509 | x_size: |
510 | dimen |
511 | { |
512 | $$ = $1; |
513 | } |
514 | | '+' dimen |
515 | { |
516 | double xa, ya, xb, yb; |
517 | |
518 | bbox(paths, &xa, &ya, &xb, &yb); |
519 | $$ = xb-xa+$2; |
520 | } |
521 | ; |
522 | |
523 | y_size: |
524 | dimen |
525 | { |
526 | $$ = $1; |
527 | } |
528 | | '+' dimen |
529 | { |
530 | double xa, ya, xb, yb; |
531 | |
532 | bbox(paths, &xa, &ya, &xb, &yb); |
533 | $$ = yb-ya+$2; |
534 | } |
535 | ; |
536 | |
537 | number: |
538 | NUM_IMP_MIL |
539 | { |
540 | $$ = $1; |
541 | } |
542 | | NUM_IMP_MM |
543 | { |
544 | $$ = $1; |
545 | } |
546 | ; |
547 | |
548 | offset_options: |
549 | { |
550 | $$ = 0; |
551 | } |
552 | | offset_option offset_options |
553 | { |
554 | $$ = $1 | $2; |
555 | |
556 | } |
557 | ; |
558 | |
559 | offset_option: |
560 | TOK_DOG |
561 | { |
562 | $$ = OO_DOG; |
563 | } |
564 | | TOK_INSIDE |
565 | { |
566 | $$ = OO_INSIDE; |
567 | } |
568 | ; |
569 | |
570 | axis: |
571 | TOK_X |
572 | { |
573 | $$ = axis_x; |
574 | } |
575 | | TOK_Y |
576 | { |
577 | $$ = axis_y; |
578 | } |
579 | ; |
580 | |
581 | opt_comma: |
582 | | ',' |
583 | ; |
584 | |
585 | opt_any: |
586 | { |
587 | $$ = 0; |
588 | } |
589 | | TOK_ANY |
590 | { |
591 | $$ = 1; |
592 | } |
593 | ; |
594 |
Branches:
master