2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
30 #include <math.h> /* M_PI */
38 #include "draw_amacro.h"
41 #define round(x) floor((double)(x) + 0.5)
45 * Stack declarations and operations to be used by the simple engine that
46 * executes the parsed aperture macros.
55 new_stack(unsigned int nuf_push
)
57 const int extra_stack_size
= 10;
60 s
= (stack_t
*)malloc(sizeof(stack_t
));
65 memset(s
, 0, sizeof(stack_t
));
67 s
->stack
= (double *)malloc(sizeof(double) * (nuf_push
+ extra_stack_size
));
73 memset(s
->stack
, 0, sizeof(double) * (nuf_push
+ extra_stack_size
));
81 free_stack(stack_t
*s
)
94 push(stack_t
*s
, double val
)
96 s
->stack
[s
->sp
++] = val
;
104 return s
->stack
[--s
->sp
];
109 * If you want to rotate a
110 * column vector v by t degrees using matrix M, use
112 * M = {{cos t, -sin t}, {sin t, cos t}} in M*v.
114 * From comp.graphics.algorithms Frequently Asked Questions
116 * Due reverse defintion of X-axis in GTK you have to negate
121 rotate_point(GdkPoint point
, int angle
)
129 sint
= sin(-(double)angle
* M_PI
/ 180.0);
130 cost
= cos(-(double)angle
* M_PI
/ 180.0);
132 returned
.x
= (int)round(cost
* (double)point
.x
- sint
* (double)point
.y
);
133 returned
.y
= (int)round(sint
* (double)point
.x
+ cost
* (double)point
.y
);
140 * Doesn't handle exposure yet and explicit x,y
143 gerbv_draw_prim1(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
146 const int diameter_idx
= 1;
147 const gint full_circle
= 23360;
148 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
149 gint dia
= round(fabs(s
->stack
[diameter_idx
] * scale
));
150 gint real_x
= x
- dia
/ 2;
151 gint real_y
= y
- dia
/ 2;
153 gdk_gc_copy(local_gc
, gc
);
154 gdk_gc_set_line_attributes(local_gc
,
155 1, /* outline always 1 pixels */
163 gdk_draw_arc(pixmap
, local_gc
, 1, real_x
, real_y
, dia
, dia
,
166 gdk_gc_unref(local_gc
);
169 } /* gerbv_draw_prim1 */
173 * Doesn't handle exposure yet and explicit x,y
175 * - should start point be included in number of points?
176 * - how thick is the outline?
179 gerbv_draw_prim4(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
182 const int nuf_points_idx
= 1;
183 const int first_x_idx
= 2;
184 const int first_y_idx
= 3;
185 const int rotext_idx
= 4;
186 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
187 int nuf_points
, point
, closed_shape
;
191 nuf_points
= (int)s
->stack
[nuf_points_idx
];
192 points
= (GdkPoint
*)malloc(sizeof(GdkPoint
) * nuf_points
);
199 * Closed (ie filled as I interpret it) shape if first and last point
203 (fabs(s
->stack
[first_x_idx
] - s
->stack
[nuf_points
* 2 + first_x_idx
]) < 0.0001) &&
204 (fabs(s
->stack
[first_y_idx
] - s
->stack
[nuf_points
* 2 + first_y_idx
]) < 0.0001);
206 rotation
= s
->stack
[nuf_points
* 2 + rotext_idx
];
207 for (point
= 0; point
< nuf_points
; point
++) {
208 points
[point
].x
= (int)round(scale
* s
->stack
[point
* 2 + first_x_idx
]);
209 points
[point
].y
= -(int)round(scale
* s
->stack
[point
* 2 + first_y_idx
]);
211 points
[point
] = rotate_point(points
[point
], rotation
);
212 points
[point
].x
+= x
;
213 points
[point
].y
+= y
;
216 gdk_gc_copy(local_gc
, gc
);
217 gdk_gc_set_line_attributes(local_gc
,
218 1, /* outline always 1 pixels */
222 gdk_draw_polygon(pixmap
, local_gc
, closed_shape
, points
, nuf_points
);
225 gdk_gc_unref(local_gc
);
227 } /* gerbv_draw_prim4 */
231 * Doesn't handle exposure yet and explicit x,y
234 gerbv_draw_prim5(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
237 const int nuf_vertices_idx
= 1;
238 const int diameter_idx
= 4;
239 const int rotation_idx
= 5;
241 double vertex
, tick
, rotation
, radius
;
247 nuf_vertices
= (int)s
->stack
[nuf_vertices_idx
];
248 points
= (GdkPoint
*)malloc(sizeof(GdkPoint
) * nuf_vertices
);
254 tick
= 2 * M_PI
/ (double)nuf_vertices
;
255 rotation
= -s
->stack
[rotation_idx
] * M_PI
/ 180.0;
256 radius
= s
->stack
[diameter_idx
] / 2.0;
257 for (i
= 0; i
< nuf_vertices
; i
++) {
258 vertex
= tick
* (double)i
+ rotation
;
259 points
[i
].x
= (int)round(scale
* radius
* cos(vertex
)) + x
;
260 points
[i
].y
= (int)round(scale
* radius
* sin(vertex
)) + y
;
263 gdk_draw_polygon(pixmap
, gc
, 1, points
, nuf_vertices
);
267 } /* gerbv_draw_prim5 */
271 * Doesn't handle exposure yet and explicit x,y
273 * - is "gap" distance between edges of circles or distance between
274 * center of line of circle?
277 gerbv_draw_prim6(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
280 const int outside_dia_idx
= 2;
281 const int ci_thickness_idx
= 3;
282 const int gap_idx
= 4;
283 const int nuf_circles_idx
= 5;
284 const int ch_thickness_idx
= 6;
285 const int ch_length_idx
= 7;
286 const int rotation_idx
= 8;
287 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
291 GdkPoint crosshair
[4];
294 gdk_gc_copy(local_gc
, gc
);
295 gdk_gc_set_line_attributes(local_gc
,
296 (int)round(scale
* s
->stack
[ci_thickness_idx
]),
301 real_dia
= s
->stack
[outside_dia_idx
] - s
->stack
[ci_thickness_idx
] / 2.0;
302 real_gap
= s
->stack
[gap_idx
] + s
->stack
[ci_thickness_idx
];
304 for (circle
= 0; circle
!= (int)s
->stack
[nuf_circles_idx
]; circle
++) {
308 const gint full_circle
= 23360;
309 gint dia
= (real_dia
- real_gap
* circle
) * scale
;
310 gdk_draw_arc(pixmap
, local_gc
, 0, x
- dia
/ 2, y
- dia
/ 2,
311 dia
, dia
, 0, full_circle
);
318 memset(crosshair
, 0, sizeof(GdkPoint
) * 4);
319 crosshair
[0].x
= (int)((s
->stack
[ch_length_idx
] / 2.0) * scale
);
320 /*crosshair[0].y = 0;*/
321 crosshair
[1].x
= -crosshair
[0].x
;
322 /*crosshair[1].y = 0;*/
323 /*crosshair[2].x = 0;*/
324 crosshair
[2].y
= crosshair
[0].x
;
325 /*crosshair[3].x = 0;*/
326 crosshair
[3].y
= -crosshair
[0].x
;
328 gdk_gc_set_line_attributes(local_gc
,
329 (int)round(scale
* s
->stack
[ch_thickness_idx
]),
334 for (point
= 0; point
< 4; point
++) {
335 crosshair
[point
] = rotate_point(crosshair
[point
],
336 s
->stack
[rotation_idx
]);
337 crosshair
[point
].x
+= x
;
338 crosshair
[point
].y
+= y
;
340 gdk_draw_line(pixmap
, local_gc
,
341 crosshair
[0].x
, crosshair
[0].y
,
342 crosshair
[1].x
, crosshair
[1].y
);
343 gdk_draw_line(pixmap
, local_gc
,
344 crosshair
[2].x
, crosshair
[2].y
,
345 crosshair
[3].x
, crosshair
[3].y
);
347 gdk_gc_unref(local_gc
);
350 } /* gerbv_draw_prim6 */
354 gerbv_draw_prim7(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
357 const int outside_dia_idx
= 2;
358 const int inside_dia_idx
= 3;
359 const int ch_thickness_idx
= 4;
360 const int rotation_idx
= 5;
361 const gint full_circle
= 23360;
364 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
366 double ci_thickness
= (s
->stack
[outside_dia_idx
] -
367 s
->stack
[inside_dia_idx
]) / 2.0;
369 gdk_gc_copy(local_gc
, gc
);
370 gdk_gc_set_line_attributes(local_gc
,
371 (int)round(scale
* ci_thickness
),
379 diameter
= (s
->stack
[inside_dia_idx
] + ci_thickness
) * scale
;
380 gdk_draw_arc(pixmap
, local_gc
, 0, x
- diameter
/ 2, y
- diameter
/ 2,
381 diameter
, diameter
, 0, full_circle
);
386 /* Calculate the end points of the crosshair */
387 for (i
= 0; i
< 4; i
++) {
388 point
[i
].x
= round((s
->stack
[outside_dia_idx
] / 2.0) * scale
);
390 point
[i
] = rotate_point(point
[i
], s
->stack
[rotation_idx
] + 90 * i
);
395 /* We must "reach out" to the outer part of the circle, hence round end */
396 gdk_gc_set_line_attributes(local_gc
,
397 (int)round(scale
* s
->stack
[ch_thickness_idx
]),
402 /* The cross hair should "cut out" parts of the circle, hence inverse */
403 gdk_gc_get_values(local_gc
, &gc_val
);
404 if (gc_val
.foreground
.pixel
== 1)
405 gc_val
.foreground
.pixel
= 0;
407 gc_val
.foreground
.pixel
= 1;
408 gdk_gc_set_foreground(local_gc
, &(gc_val
.foreground
));
410 /* Draw the actual cross */
411 gdk_draw_line(pixmap
, local_gc
,
412 point
[0].x
, point
[0].y
, point
[2].x
, point
[2].y
);
413 gdk_draw_line(pixmap
, local_gc
,
414 point
[1].x
, point
[1].y
, point
[3].x
, point
[3].y
);
416 gdk_gc_unref(local_gc
);
419 } /* gerbv_draw_prim7 */
423 * Doesn't handle exposure yet and explicit x,y
426 gerbv_draw_prim20(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
429 const int linewidth_idx
= 1;
430 const int start_x_idx
= 2;
431 const int start_y_idx
= 3;
432 const int end_x_idx
= 4;
433 const int end_y_idx
= 5;
434 const int rotation_idx
= 6;
435 const int nuf_points
= 2;
436 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
437 GdkPoint points
[nuf_points
];
440 gdk_gc_copy(local_gc
, gc
);
442 gdk_gc_set_line_attributes(local_gc
,
443 (int)round(scale
* s
->stack
[linewidth_idx
]),
448 points
[0].x
= (s
->stack
[start_x_idx
] * scale
);
449 points
[0].y
= (s
->stack
[start_y_idx
] * scale
);
450 points
[1].x
= (s
->stack
[end_x_idx
] * scale
);
451 points
[1].y
= (s
->stack
[end_y_idx
] * scale
);
453 for (i
= 0; i
< nuf_points
; i
++) {
454 points
[i
] = rotate_point(points
[i
], s
->stack
[rotation_idx
]);
455 points
[i
].x
= x
+ points
[i
].x
;
456 points
[i
].y
= y
- points
[i
].y
;
459 gdk_draw_line(pixmap
, local_gc
,
460 points
[0].x
, points
[0].y
,
461 points
[1].x
, points
[1].y
);
463 gdk_gc_unref(local_gc
);
466 } /* gerbv_draw_prim20 */
470 * Doesn't handle exposure yet and explicit x,y
473 gerbv_draw_prim21(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
476 const int width_idx
= 1;
477 const int height_idx
= 2;
478 const int rotation_idx
= 5;
479 const int nuf_points
= 4;
480 GdkPoint points
[nuf_points
];
481 int half_width
, half_height
;
484 half_width
= (int)round(s
->stack
[width_idx
] * scale
/ 2.0);
485 half_height
=(int)round(s
->stack
[height_idx
] * scale
/ 2.0);
487 points
[0].x
= half_width
;
488 points
[0].y
= half_height
;
490 points
[1].x
= half_width
;
491 points
[1].y
= -half_height
;
493 points
[2].x
= -half_width
;
494 points
[2].y
= -half_height
;
496 points
[3].x
= -half_width
;
497 points
[3].y
= half_height
;
499 for (i
= 0; i
< nuf_points
; i
++) {
500 points
[i
] = rotate_point(points
[i
], s
->stack
[rotation_idx
]);
505 gdk_draw_polygon(pixmap
, gc
, 1, points
, nuf_points
);
508 } /* gerbv_draw_prim21 */
512 * Doesn't handle exposure yet and explicit x,y
515 gerbv_draw_prim22(GdkPixmap
*pixmap
, GdkGC
*gc
, stack_t
*s
, int scale
,
518 const int width_idx
= 1;
519 const int height_idx
= 2;
520 const int x_lower_left_idx
= 3;
521 const int y_lower_left_idx
= 4;
522 const int rotation_idx
= 5;
523 const int nuf_points
= 4;
524 GdkPoint points
[nuf_points
];
527 points
[0].x
= (int)round(s
->stack
[x_lower_left_idx
] * scale
);
528 points
[0].y
= (int)round(s
->stack
[y_lower_left_idx
] * scale
);
530 points
[1].x
= (int)round((s
->stack
[x_lower_left_idx
] + s
->stack
[width_idx
])
532 points
[1].y
= (int)round(s
->stack
[y_lower_left_idx
] * scale
);
534 points
[2].x
= (int)round((s
->stack
[x_lower_left_idx
] + s
->stack
[width_idx
])
536 points
[2].y
= (int)round((s
->stack
[y_lower_left_idx
] - s
->stack
[height_idx
])
539 points
[3].x
= (int)round(s
->stack
[x_lower_left_idx
] * scale
);
540 points
[3].y
= (int)round((s
->stack
[y_lower_left_idx
] - s
->stack
[height_idx
])
543 for (i
= 0; i
< nuf_points
; i
++) {
544 points
[i
] = rotate_point(points
[i
], s
->stack
[rotation_idx
]);
549 gdk_draw_polygon(pixmap
, gc
, 1, points
, nuf_points
);
552 } /* gerbv_draw_prim22 */
556 gerbv_draw_amacro(GdkPixmap
*pixmap
, GdkGC
*gc
,
557 instruction_t
*program
, unsigned int nuf_push
,
558 double *parameters
, int scale
, gint x
, gint y
)
560 stack_t
*s
= new_stack(nuf_push
);
564 for(ip
= program
; ip
!= NULL
; ip
= ip
->next
) {
569 push(s
, ip
->data
.fval
);
572 push(s
, parameters
[ip
->data
.ival
- 1]);
575 push(s
, pop(s
) + pop(s
));
578 push(s
, -pop(s
) + pop(s
));
581 push(s
, pop(s
) * pop(s
));
584 push(s
, 1 / ((pop(s
) / pop(s
))));
587 switch(ip
->data
.ival
) {
589 gerbv_draw_prim1(pixmap
, gc
, s
, scale
, x
, y
);
592 gerbv_draw_prim4(pixmap
, gc
, s
, scale
, x
, y
);
595 gerbv_draw_prim5(pixmap
, gc
, s
, scale
, x
, y
);
598 gerbv_draw_prim6(pixmap
, gc
, s
, scale
, x
, y
);
601 gerbv_draw_prim7(pixmap
, gc
, s
, scale
, x
, y
);
605 gerbv_draw_prim20(pixmap
, gc
, s
, scale
, x
, y
);
608 gerbv_draw_prim21(pixmap
, gc
, s
, scale
, x
, y
);
611 gerbv_draw_prim22(pixmap
, gc
, s
, scale
, x
, y
);
617 * Here we reset the stack pointer. It's not general correct
618 * correct to do this, but since I know how the compiler works
619 * I can do this. The correct way to do this should be to
620 * subtract number of used elements in each primitive operation.
630 } /* gerbv_draw_amacro */