2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 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
25 \brief GDK rendering functions
35 #include <math.h> /* ceil(), atan2() */
46 #define round(x) ceil((double)(x))
48 #define dprintf if(DEBUG) printf
51 * If you want to rotate a
52 * column vector v by t degrees using matrix M, use
54 * M = {{cos t, -sin t}, {sin t, cos t}} in M*v.
56 * From comp.graphics.algorithms Frequently Asked Questions
58 * Due reverse defintion of X-axis in GTK you have to negate
63 rotate_point(GdkPoint point
, int angle
)
71 sint
= sin(-(double)angle
* M_PI
/ 180.0);
72 cost
= cos(-(double)angle
* M_PI
/ 180.0);
74 returned
.x
= (int)round(cost
* (double)point
.x
- sint
* (double)point
.y
);
75 returned
.y
= (int)round(sint
* (double)point
.x
+ cost
* (double)point
.y
);
82 * Aperture macro primitive 1 (Circle)
85 gerbv_gdk_draw_prim1(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
86 double scale
, gint x
, gint y
)
88 const int exposure_idx
= 0;
89 const int diameter_idx
= 1;
90 const int x_offset_idx
= 2;
91 const int y_offset_idx
= 3;
92 const gint full_circle
= 23360;
93 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
94 gint dia
= round(fabs(p
[diameter_idx
] * scale
));
95 gint real_x
= x
- dia
/ 2;
96 gint real_y
= y
- dia
/ 2;
99 gdk_gc_copy(local_gc
, gc
);
101 real_x
+= (int)(p
[x_offset_idx
] * (double)scale
);
102 real_y
-= (int)(p
[y_offset_idx
] * (double)scale
);
105 if (p
[exposure_idx
] == 0.0) {
107 gdk_gc_set_foreground(local_gc
, &color
);
110 gdk_gc_set_line_attributes(local_gc
,
111 1, /* outline always 1 pixels */
119 gdk_draw_arc(pixmap
, local_gc
, 1, real_x
, real_y
, dia
, dia
,
122 gdk_gc_unref(local_gc
);
125 } /* gerbv_gdk_draw_prim1 */
129 * Aperture macro primitive 4 (outline)
130 * - Start point is not included in number of points.
131 * - Outline is 1 pixel.
134 gerbv_gdk_draw_prim4(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
135 double scale
, gint x
, gint y
)
137 const int exposure_idx
= 0;
138 const int nuf_points_idx
= 1;
139 const int first_x_idx
= 2;
140 const int first_y_idx
= 3;
141 const int rotext_idx
= 4;
142 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
143 int nuf_points
, point
;
148 /* Include start point */
149 nuf_points
= (int)p
[nuf_points_idx
] + 1;
150 points
= (GdkPoint
*)g_malloc(sizeof(GdkPoint
) * nuf_points
);
156 rotation
= p
[(nuf_points
- 1) * 2 + rotext_idx
];
157 for (point
= 0; point
< nuf_points
; point
++) {
158 points
[point
].x
= (int)round(scale
* p
[point
* 2 + first_x_idx
]);
159 points
[point
].y
= -(int)round(scale
* p
[point
* 2 + first_y_idx
]);
161 points
[point
] = rotate_point(points
[point
], rotation
);
162 points
[point
].x
+= x
;
163 points
[point
].y
+= y
;
166 gdk_gc_copy(local_gc
, gc
);
169 if (p
[exposure_idx
] == 0.0) {
171 gdk_gc_set_foreground(local_gc
, &color
);
174 gdk_gc_set_line_attributes(local_gc
,
175 1, /* outline always 1 pixels */
179 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_points
);
183 gdk_gc_unref(local_gc
);
186 } /* gerbv_gdk_draw_prim4 */
190 * Aperture macro primitive 5 (polygon)
193 gerbv_gdk_draw_prim5(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
194 double scale
, gint x
, gint y
)
196 const int exposure_idx
= 0;
197 const int nuf_vertices_idx
= 1;
198 const int center_x_idx
= 2;
199 const int center_y_idx
= 3;
200 const int diameter_idx
= 4;
201 const int rotation_idx
= 5;
203 double vertex
, tick
, rotation
, radius
;
205 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
208 nuf_vertices
= (int)p
[nuf_vertices_idx
];
209 points
= (GdkPoint
*)g_malloc(sizeof(GdkPoint
) * nuf_vertices
);
215 gdk_gc_copy(local_gc
, gc
);
218 if (p
[exposure_idx
] == 0.0) {
220 gdk_gc_set_foreground(local_gc
, &color
);
223 tick
= 2 * M_PI
/ (double)nuf_vertices
;
224 rotation
= -p
[rotation_idx
] * M_PI
/ 180.0;
225 radius
= p
[diameter_idx
] / 2.0;
226 for (i
= 0; i
< nuf_vertices
; i
++) {
227 vertex
= tick
* (double)i
+ rotation
;
228 points
[i
].x
= (int)round(scale
* radius
* cos(vertex
)) + x
+
230 points
[i
].y
= (int)round(scale
* radius
* sin(vertex
)) + y
+
234 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_vertices
);
236 gdk_gc_unref(local_gc
);
240 } /* gerbv_gdk_draw_prim5 */
244 * Doesn't handle and explicit x,y yet
246 * - is "gap" distance between edges of circles or distance between
247 * center of line of circle?
250 gerbv_gdk_draw_prim6(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
251 double scale
, gint x
, gint y
)
253 const int outside_dia_idx
= 2;
254 const int ci_thickness_idx
= 3;
255 const int gap_idx
= 4;
256 const int nuf_circles_idx
= 5;
257 const int ch_thickness_idx
= 6;
258 const int ch_length_idx
= 7;
259 const int rotation_idx
= 8;
260 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
264 GdkPoint crosshair
[4];
267 gdk_gc_copy(local_gc
, gc
);
268 gdk_gc_set_line_attributes(local_gc
,
269 (int)round(scale
* p
[ci_thickness_idx
]),
274 real_dia
= p
[outside_dia_idx
] - p
[ci_thickness_idx
] / 2.0;
275 real_gap
= p
[gap_idx
] + p
[ci_thickness_idx
];
277 for (circle
= 0; circle
!= (int)p
[nuf_circles_idx
]; circle
++) {
281 const gint full_circle
= 23360;
282 gint dia
= (real_dia
- real_gap
* circle
) * scale
;
283 gdk_draw_arc(pixmap
, local_gc
, 0, x
- dia
/ 2, y
- dia
/ 2,
284 dia
, dia
, 0, full_circle
);
291 memset(crosshair
, 0, sizeof(GdkPoint
) * 4);
292 crosshair
[0].x
= (int)((p
[ch_length_idx
] / 2.0) * scale
);
293 /*crosshair[0].y = 0;*/
294 crosshair
[1].x
= -crosshair
[0].x
;
295 /*crosshair[1].y = 0;*/
296 /*crosshair[2].x = 0;*/
297 crosshair
[2].y
= crosshair
[0].x
;
298 /*crosshair[3].x = 0;*/
299 crosshair
[3].y
= -crosshair
[0].x
;
301 gdk_gc_set_line_attributes(local_gc
,
302 (int)round(scale
* p
[ch_thickness_idx
]),
307 for (point
= 0; point
< 4; point
++) {
308 crosshair
[point
] = rotate_point(crosshair
[point
],
310 crosshair
[point
].x
+= x
;
311 crosshair
[point
].y
+= y
;
313 gdk_draw_line(pixmap
, local_gc
,
314 crosshair
[0].x
, crosshair
[0].y
,
315 crosshair
[1].x
, crosshair
[1].y
);
316 gdk_draw_line(pixmap
, local_gc
,
317 crosshair
[2].x
, crosshair
[2].y
,
318 crosshair
[3].x
, crosshair
[3].y
);
320 gdk_gc_unref(local_gc
);
323 } /* gerbv_gdk_draw_prim6 */
327 gerbv_gdk_draw_prim7(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
328 double scale
, gint x
, gint y
)
330 const int outside_dia_idx
= 2;
331 const int inside_dia_idx
= 3;
332 const int ch_thickness_idx
= 4;
333 const int rotation_idx
= 5;
334 const gint full_circle
= 23360;
337 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
339 double ci_thickness
= (p
[outside_dia_idx
] -
340 p
[inside_dia_idx
]) / 2.0;
342 gdk_gc_copy(local_gc
, gc
);
343 gdk_gc_set_line_attributes(local_gc
,
344 (int)round(scale
* ci_thickness
),
352 diameter
= (p
[inside_dia_idx
] + ci_thickness
) * scale
;
353 gdk_draw_arc(pixmap
, local_gc
, 0, x
- diameter
/ 2, y
- diameter
/ 2,
354 diameter
, diameter
, 0, full_circle
);
359 /* Calculate the end points of the crosshair */
360 /* GDK doesn't always remove all of the circle (round of error probably)
361 I extend the crosshair line with 2 (one pixel in each end) to make
362 sure all of the circle is removed with the crosshair */
363 for (i
= 0; i
< 4; i
++) {
364 point
[i
].x
= round((p
[outside_dia_idx
] / 2.0) * scale
) + 2;
366 point
[i
] = rotate_point(point
[i
], p
[rotation_idx
] + 90 * i
);
371 gdk_gc_set_line_attributes(local_gc
,
372 (int)round(scale
* p
[ch_thickness_idx
]),
377 /* The cross hair should "cut out" parts of the circle, hence inverse */
378 gdk_gc_get_values(local_gc
, &gc_val
);
379 if (gc_val
.foreground
.pixel
== 1)
380 gc_val
.foreground
.pixel
= 0;
382 gc_val
.foreground
.pixel
= 1;
383 gdk_gc_set_foreground(local_gc
, &(gc_val
.foreground
));
385 /* Draw the actual cross */
386 gdk_draw_line(pixmap
, local_gc
,
387 point
[0].x
, point
[0].y
, point
[2].x
, point
[2].y
);
388 gdk_draw_line(pixmap
, local_gc
,
389 point
[1].x
, point
[1].y
, point
[3].x
, point
[3].y
);
391 gdk_gc_unref(local_gc
);
394 } /* gerbv_gdk_draw_prim7 */
398 * Doesn't handle and explicit x,y yet
401 gerbv_gdk_draw_prim20(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
402 double scale
, gint x
, gint y
)
404 const int exposure_idx
= 0;
405 const int linewidth_idx
= 1;
406 const int start_x_idx
= 2;
407 const int start_y_idx
= 3;
408 const int end_x_idx
= 4;
409 const int end_y_idx
= 5;
410 const int rotation_idx
= 6;
411 const int nuf_points
= 2;
412 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
413 GdkPoint points
[nuf_points
];
417 gdk_gc_copy(local_gc
, gc
);
420 if (p
[exposure_idx
] == 0.0) {
422 gdk_gc_set_foreground(local_gc
, &color
);
425 gdk_gc_set_line_attributes(local_gc
,
426 (int)round(scale
* p
[linewidth_idx
]),
431 points
[0].x
= (p
[start_x_idx
] * scale
);
432 points
[0].y
= (p
[start_y_idx
] * scale
);
433 points
[1].x
= (p
[end_x_idx
] * scale
);
434 points
[1].y
= (p
[end_y_idx
] * scale
);
436 for (i
= 0; i
< nuf_points
; i
++) {
437 points
[i
] = rotate_point(points
[i
], -p
[rotation_idx
]);
438 points
[i
].x
= x
+ points
[i
].x
;
439 points
[i
].y
= y
- points
[i
].y
;
442 gdk_draw_line(pixmap
, local_gc
,
443 points
[0].x
, points
[0].y
,
444 points
[1].x
, points
[1].y
);
446 gdk_gc_unref(local_gc
);
449 } /* gerbv_gdk_draw_prim20 */
453 gerbv_gdk_draw_prim21(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
454 double scale
, gint x
, gint y
)
456 const int exposure_idx
= 0;
457 const int width_idx
= 1;
458 const int height_idx
= 2;
459 const int exp_x_idx
= 3;
460 const int exp_y_idx
= 4;
461 const int rotation_idx
= 5;
462 const int nuf_points
= 4;
463 GdkPoint points
[nuf_points
];
465 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
466 int half_width
, half_height
;
469 half_width
= (int)round(p
[width_idx
] * scale
/ 2.0);
470 half_height
=(int)round(p
[height_idx
] * scale
/ 2.0);
472 points
[0].x
= half_width
;
473 points
[0].y
= half_height
;
475 points
[1].x
= half_width
;
476 points
[1].y
= -half_height
;
478 points
[2].x
= -half_width
;
479 points
[2].y
= -half_height
;
481 points
[3].x
= -half_width
;
482 points
[3].y
= half_height
;
484 for (i
= 0; i
< nuf_points
; i
++) {
485 points
[i
] = rotate_point(points
[i
], p
[rotation_idx
]);
486 points
[i
].x
+= (x
+ (int)(p
[exp_x_idx
] * scale
));
487 points
[i
].y
+= (y
- (int)(p
[exp_y_idx
] * scale
));
490 gdk_gc_copy(local_gc
, gc
);
493 if (p
[exposure_idx
] == 0.0) {
495 gdk_gc_set_foreground(local_gc
, &color
);
498 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_points
);
500 gdk_gc_unref(local_gc
);
503 } /* gerbv_gdk_draw_prim21 */
507 * Doesn't handle explicit x,y yet
510 gerbv_gdk_draw_prim22(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
511 double scale
, gint x
, gint y
)
513 const int exposure_idx
= 0;
514 const int width_idx
= 1;
515 const int height_idx
= 2;
516 const int x_lower_left_idx
= 3;
517 const int y_lower_left_idx
= 4;
518 const int rotation_idx
= 5;
519 const int nuf_points
= 4;
520 GdkPoint points
[nuf_points
];
521 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
525 points
[0].x
= (int)round(p
[x_lower_left_idx
] * scale
);
526 points
[0].y
= (int)round(p
[y_lower_left_idx
] * scale
);
528 points
[1].x
= (int)round((p
[x_lower_left_idx
] + p
[width_idx
])
530 points
[1].y
= (int)round(p
[y_lower_left_idx
] * scale
);
532 points
[2].x
= (int)round((p
[x_lower_left_idx
] + p
[width_idx
])
534 points
[2].y
= (int)round((p
[y_lower_left_idx
] - p
[height_idx
])
537 points
[3].x
= (int)round(p
[x_lower_left_idx
] * scale
);
538 points
[3].y
= (int)round((p
[y_lower_left_idx
] - p
[height_idx
])
541 for (i
= 0; i
< nuf_points
; i
++) {
542 points
[i
] = rotate_point(points
[i
], p
[rotation_idx
]);
547 gdk_gc_copy(local_gc
, gc
);
550 if (p
[exposure_idx
] == 0.0) {
552 gdk_gc_set_foreground(local_gc
, &color
);
555 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_points
);
557 gdk_gc_unref(local_gc
);
560 } /* gerbv_gdk_draw_prim22 */
564 gerbv_gdk_draw_amacro(GdkPixmap
*pixmap
, GdkGC
*gc
,
565 gerbv_simplified_amacro_t
*s
, double scale
,
568 gerbv_simplified_amacro_t
*ls
= s
;
570 dprintf("Drawing simplified aperture macros:\n");
574 case GERBV_APTYPE_MACRO_CIRCLE
:
575 gerbv_gdk_draw_prim1(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
576 dprintf(" Circle\n");
578 case GERBV_APTYPE_MACRO_OUTLINE
:
579 gerbv_gdk_draw_prim4(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
580 dprintf(" Outline\n");
582 case GERBV_APTYPE_MACRO_POLYGON
:
583 gerbv_gdk_draw_prim5(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
584 dprintf(" Polygon\n");
586 case GERBV_APTYPE_MACRO_MOIRE
:
587 gerbv_gdk_draw_prim6(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
588 dprintf(" Moiré\n");
590 case GERBV_APTYPE_MACRO_THERMAL
:
591 gerbv_gdk_draw_prim7(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
592 dprintf(" Thermal\n");
594 case GERBV_APTYPE_MACRO_LINE20
:
595 gerbv_gdk_draw_prim20(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
596 dprintf(" Line 20\n");
598 case GERBV_APTYPE_MACRO_LINE21
:
599 gerbv_gdk_draw_prim21(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
600 dprintf(" Line 21\n");
602 case GERBV_APTYPE_MACRO_LINE22
:
603 gerbv_gdk_draw_prim22(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
604 dprintf(" Line 22\n");
607 GERB_FATAL_ERROR("Unknown simplified aperture macro");
613 } /* gerbv_gdk_draw_amacro */
617 * Draws a circle _centered_ at x,y with diameter dia
620 gerbv_gdk_draw_circle(GdkPixmap
*pixmap
, GdkGC
*gc
,
621 gint filled
, gint x
, gint y
, gint dia
)
623 static const gint full_circle
= 23360;
624 gint real_x
= x
- dia
/ 2;
625 gint real_y
= y
- dia
/ 2;
627 gdk_draw_arc(pixmap
, gc
, filled
, real_x
, real_y
, dia
, dia
, 0, full_circle
);
630 } /* gerbv_gdk_draw_circle */
634 * Draws a rectangle _centered_ at x,y with sides x_side, y_side
637 gerbv_gdk_draw_rectangle(GdkPixmap
*pixmap
, GdkGC
*gc
,
638 gint filled
, gint x
, gint y
, gint x_side
, gint y_side
)
641 gint real_x
= x
- x_side
/ 2;
642 gint real_y
= y
- y_side
/ 2;
644 gdk_draw_rectangle(pixmap
, gc
, filled
, real_x
, real_y
, x_side
, y_side
);
647 } /* gerbv_gdk_draw_rectangle */
651 * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
654 gerbv_gdk_draw_oval(GdkPixmap
*pixmap
, GdkGC
*gc
,
655 gint filled
, gint x
, gint y
, gint x_axis
, gint y_axis
)
658 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
660 gdk_gc_copy(local_gc
, gc
);
662 if (x_axis
> y_axis
) {
664 delta
= x_axis
/ 2 - y_axis
/ 2;
665 gdk_gc_set_line_attributes(local_gc
, y_axis
,
669 gdk_draw_line(pixmap
, local_gc
, x
- delta
, y
, x
+ delta
, y
);
672 delta
= y_axis
/ 2 - x_axis
/ 2;
673 gdk_gc_set_line_attributes(local_gc
, x_axis
,
677 gdk_draw_line(pixmap
, local_gc
, x
, y
- delta
, x
, y
+ delta
);
680 gdk_gc_unref(local_gc
);
683 } /* gerbv_gdk_draw_oval */
688 * Draws an arc _centered_ at x,y
689 * direction: 0 counterclockwise, 1 clockwise
692 gerbv_gdk_draw_arc(GdkPixmap
*pixmap
, GdkGC
*gc
,
694 int width
, int height
,
695 double angle1
, double angle2
)
697 gint real_x
= x
- width
/ 2;
698 gint real_y
= y
- height
/ 2;
700 gdk_draw_arc(pixmap
, gc
, FALSE
, real_x
, real_y
, width
, height
,
701 (gint
)(angle1
* 64.0), (gint
)(angle2
- angle1
) * 64.0);
704 } /* gerbv_gdk_draw_arc */
707 draw_gdk_render_polygon_object (gerbv_net_t
*oldNet
, gerbv_image_t
*image
, double sr_x
, double sr_y
,
708 cairo_matrix_t
*fullMatrix
, cairo_matrix_t
*scaleMatrix
, GdkGC
*gc
, GdkGC
*pgc
,
709 GdkPixmap
**pixmap
) {
710 gerbv_net_t
*currentNet
;
711 gint x1
,x2
,y1
,y2
,cp_x
=0,cp_y
=0,cir_width
=0,cir_height
=0;
712 GdkPoint
*points
= NULL
;
713 int pointArraySize
=0;
714 int curr_point_idx
= 0;
716 gdouble angleDiff
, tempX
, tempY
;
718 /* save the first net in the polygon as the "ID" net pointer
719 in case we are saving this net to the selection array */
723 for (currentNet
= oldNet
->next
; currentNet
!=NULL
; currentNet
= currentNet
->next
){
724 tempX
= currentNet
->start_x
+ sr_x
;
725 tempY
= currentNet
->start_y
+ sr_y
;
726 cairo_matrix_transform_point (fullMatrix
, &tempX
, &tempY
);
727 x1
= (int)round(tempX
);
728 y1
= (int)round(tempY
);
730 tempX
= currentNet
->stop_x
+ sr_x
;
731 tempY
= currentNet
->stop_y
+ sr_y
;
732 cairo_matrix_transform_point (fullMatrix
, &tempX
, &tempY
);
733 x2
= (int)round(tempX
);
734 y2
= (int)round(tempY
);
737 * If circle segment, scale and translate that one too
739 if (currentNet
->cirseg
) {
740 tempX
= currentNet
->cirseg
->width
;
741 tempY
= currentNet
->cirseg
->height
;
742 cairo_matrix_transform_point (scaleMatrix
, &tempX
, &tempY
);
743 cir_width
= (int)round(tempX
);
744 cir_height
= (int)round(tempY
);
746 tempX
= currentNet
->cirseg
->cp_x
+ sr_x
;
747 tempY
= currentNet
->cirseg
->cp_y
+ sr_y
;
748 cairo_matrix_transform_point (fullMatrix
, &tempX
, &tempY
);
749 cp_x
= (int)round(tempX
);
750 cp_y
= (int)round(tempY
);
753 switch (currentNet
->interpolation
) {
754 case GERBV_INTERPOLATION_x10
:
755 case GERBV_INTERPOLATION_LINEARx01
:
756 case GERBV_INTERPOLATION_LINEARx001
:
757 case GERBV_INTERPOLATION_LINEARx1
:
758 if (pointArraySize
< (curr_point_idx
+ 1)) {
759 points
= (GdkPoint
*)g_realloc(points
,sizeof(GdkPoint
) * (curr_point_idx
+ 1));
760 pointArraySize
= (curr_point_idx
+ 1);
762 points
[curr_point_idx
].x
= x2
;
763 points
[curr_point_idx
].y
= y2
;
766 case GERBV_INTERPOLATION_CW_CIRCULAR
:
767 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
768 /* we need to chop up the arc into small lines for rendering
770 angleDiff
= currentNet
->cirseg
->angle2
- currentNet
->cirseg
->angle1
;
771 steps
= (int) abs(angleDiff
);
772 if (pointArraySize
< (curr_point_idx
+ steps
)) {
773 points
= (GdkPoint
*)g_realloc(points
,sizeof(GdkPoint
) * (curr_point_idx
+ steps
));
774 pointArraySize
= (curr_point_idx
+ steps
);
776 for (i
=0; i
<steps
; i
++){
777 points
[curr_point_idx
].x
= cp_x
+ cir_width
/ 2.0 * cos ((currentNet
->cirseg
->angle1
+
778 (angleDiff
* i
) / steps
)*M_PI
/180);
779 points
[curr_point_idx
].y
= cp_y
- cir_width
/ 2.0 * sin ((currentNet
->cirseg
->angle1
+
780 (angleDiff
* i
) / steps
)*M_PI
/180);
784 case GERBV_INTERPOLATION_PAREA_END
:
785 gdk_gc_copy(pgc
, gc
);
786 gdk_gc_set_line_attributes(pgc
, 1,
790 gdk_draw_polygon(*pixmap
, pgc
, 1, points
, curr_point_idx
);
802 draw_gdk_apply_netstate_transformation (cairo_matrix_t
*fullMatrix
, cairo_matrix_t
*scaleMatrix
,
803 gerbv_netstate_t
*state
) {
804 /* apply scale factor */
805 cairo_matrix_scale (fullMatrix
, state
->scaleA
, state
->scaleB
);
806 cairo_matrix_scale (scaleMatrix
, state
->scaleA
, state
->scaleB
);
808 cairo_matrix_translate (fullMatrix
, state
->offsetA
, state
->offsetB
);
810 switch (state
->mirrorState
) {
811 case GERBV_MIRROR_STATE_FLIPA
:
812 cairo_matrix_scale (fullMatrix
, -1, 1);
813 cairo_matrix_scale (scaleMatrix
, -1, 1);
815 case GERBV_MIRROR_STATE_FLIPB
:
816 cairo_matrix_scale (fullMatrix
, 1, -1);
817 cairo_matrix_scale (scaleMatrix
, -1, 1);
819 case GERBV_MIRROR_STATE_FLIPAB
:
820 cairo_matrix_scale (fullMatrix
, -1, -1);
821 cairo_matrix_scale (scaleMatrix
, -1, 1);
826 /* finally, apply axis select */
827 if (state
->axisSelect
== GERBV_AXIS_SELECT_SWAPAB
) {
828 /* we do this by rotating 270 (counterclockwise, then mirroring
830 cairo_matrix_rotate (fullMatrix
, 3 * M_PI
/ 2);
831 cairo_matrix_scale (fullMatrix
, 1, -1);
836 * Convert a gerber image to a GDK clip mask to be used when creating pixmap
839 draw_gdk_image_to_pixmap(GdkPixmap
**pixmap
, gerbv_image_t
*image
,
840 double scale
, double trans_x
, double trans_y
,
842 gerbv_selection_info_t
*selectionInfo
, gerbv_render_info_t
*renderInfo
,
843 gerbv_user_transformation_t transform
)
845 GdkGC
*gc
= gdk_gc_new(*pixmap
);
846 GdkGC
*pgc
= gdk_gc_new(*pixmap
);
847 GdkGCValues gc_values
;
848 struct gerbv_net
*net
;
849 gerbv_netstate_t
*oldState
;
850 gerbv_layer_t
*oldLayer
;
852 glong xlong1
, ylong1
, xlong2
, ylong2
;
854 int cir_width
= 0, cir_height
= 0;
855 int cp_x
= 0, cp_y
= 0;
856 GdkColor transparent
, opaque
;
857 gerbv_polarity_t polarity
;
859 gdouble minX
=0,minY
=0,maxX
=0,maxY
=0;
861 if (transform
.inverted
) {
862 if (image
->info
->polarity
== GERBV_POLARITY_POSITIVE
)
863 polarity
= GERBV_POLARITY_NEGATIVE
;
865 polarity
= GERBV_POLARITY_POSITIVE
;
867 polarity
= image
->info
->polarity
;
869 if (drawMode
== DRAW_SELECTIONS
)
870 polarity
= GERBV_POLARITY_POSITIVE
;
872 gboolean useOptimizations
= TRUE
;
873 // if the user is using any transformations for this layer, then don't bother using rendering
875 if ((fabs(transform
.translateX
) > 0.00001) ||
876 (fabs(transform
.translateY
) > 0.00001) ||
877 (fabs(transform
.scaleX
- 1) > 0.00001) ||
878 (fabs(transform
.scaleY
- 1) > 0.00001) ||
879 (fabs(transform
.rotation
) > 0.00001) ||
880 transform
.mirrorAroundX
|| transform
.mirrorAroundY
)
881 useOptimizations
= FALSE
;
883 // calculate the transformation matrix for the user_transformation options
884 cairo_matrix_t fullMatrix
, scaleMatrix
;
885 cairo_matrix_init (&fullMatrix
, 1, 0, 0, 1, 0, 0);
886 cairo_matrix_init (&scaleMatrix
, 1, 0, 0, 1, 0, 0);
888 cairo_matrix_translate (&fullMatrix
, trans_x
, trans_y
);
889 cairo_matrix_scale (&fullMatrix
, scale
, scale
);
890 cairo_matrix_scale (&scaleMatrix
, scale
, scale
);
893 cairo_matrix_translate (&fullMatrix
, transform
.translateX
, transform
.translateY
);
894 // don't use mirroring for the scale matrix
895 gdouble scaleX
= transform
.scaleX
;
896 gdouble scaleY
= -1*transform
.scaleY
;
897 cairo_matrix_scale (&scaleMatrix
, scaleX
, -1*scaleY
);
898 if (transform
.mirrorAroundX
)
900 if (transform
.mirrorAroundY
)
903 cairo_matrix_scale (&fullMatrix
, scaleX
, scaleY
);
904 /* do image rotation */
905 cairo_matrix_rotate (&fullMatrix
, transform
.rotation
);
906 //cairo_matrix_rotate (&scaleMatrix, transform.rotation);
908 /* do image rotation */
909 cairo_matrix_rotate (&fullMatrix
, image
->info
->imageRotation
);
911 if (useOptimizations
) {
912 minX
= renderInfo
->lowerLeftX
;
913 minY
= renderInfo
->lowerLeftY
;
914 maxX
= renderInfo
->lowerLeftX
+ (renderInfo
->displayWidth
/
915 renderInfo
->scaleFactorX
);
916 maxY
= renderInfo
->lowerLeftY
+ (renderInfo
->displayHeight
/
917 renderInfo
->scaleFactorY
);
920 if (image
== NULL
|| image
->netlist
== NULL
) {
922 * Destroy GCs before exiting
930 /* Set up the two "colors" we have */
931 opaque
.pixel
= 0; /* opaque will not let color through */
932 transparent
.pixel
= 1; /* transparent will let color through */
935 * Clear clipmask and set draw color depending image on image polarity
937 if (polarity
== GERBV_POLARITY_NEGATIVE
) {
938 gdk_gc_set_foreground(gc
, &transparent
);
939 gdk_draw_rectangle(*pixmap
, gc
, TRUE
, 0, 0, -1, -1);
940 gdk_gc_set_foreground(gc
, &opaque
);
942 gdk_gc_set_foreground(gc
, &opaque
);
943 gdk_draw_rectangle(*pixmap
, gc
, TRUE
, 0, 0, -1, -1);
944 gdk_gc_set_foreground(gc
, &transparent
);
946 oldLayer
= image
->layers
;
947 oldState
= image
->states
;
948 for (net
= image
->netlist
->next
; net
!= NULL
; net
= gerbv_image_return_next_renderable_object(net
)) {
949 int repeat_X
=1, repeat_Y
=1;
950 double repeat_dist_X
=0.0, repeat_dist_Y
=0.0;
951 int repeat_i
, repeat_j
;
954 * If step_and_repeat (%SR%) used, repeat the drawing;
956 repeat_X
= net
->layer
->stepAndRepeat
.X
;
957 repeat_Y
= net
->layer
->stepAndRepeat
.Y
;
958 repeat_dist_X
= net
->layer
->stepAndRepeat
.dist_X
;
959 repeat_dist_Y
= net
->layer
->stepAndRepeat
.dist_Y
;
961 /* check if this is a new netstate */
962 if (net
->state
!= oldState
){
963 /* it's a new state, so recalculate the new transformation matrix
965 draw_gdk_apply_netstate_transformation (&fullMatrix
, &scaleMatrix
, net
->state
);
966 oldState
= net
->state
;
968 /* check if this is a new layer */
969 /* for now, only do layer rotations in GDK rendering */
970 if (net
->layer
!= oldLayer
){
971 cairo_matrix_rotate (&fullMatrix
, net
->layer
->rotation
);
972 oldLayer
= net
->layer
;
975 if (drawMode
== DRAW_SELECTIONS
) {
977 gboolean foundNet
= FALSE
;
979 for (i
=0; i
<selectionInfo
->selectedNodeArray
->len
; i
++){
980 gerbv_selection_item_t sItem
= g_array_index (selectionInfo
->selectedNodeArray
,
981 gerbv_selection_item_t
, i
);
982 if (sItem
.net
== net
)
989 for(repeat_i
= 0; repeat_i
< repeat_X
; repeat_i
++) {
990 for(repeat_j
= 0; repeat_j
< repeat_Y
; repeat_j
++) {
991 double sr_x
= repeat_i
* repeat_dist_X
;
992 double sr_y
= repeat_j
* repeat_dist_Y
;
994 if ((useOptimizations
)&&((net
->boundingBox
.right
+sr_x
< minX
)
995 || (net
->boundingBox
.left
+sr_y
> maxX
)
996 || (net
->boundingBox
.top
+sr_y
< minY
)
997 || (net
->boundingBox
.bottom
+sr_y
> maxY
))) {
1002 * If circle segment, scale and translate that one too
1005 tempX
= net
->cirseg
->width
;
1006 tempY
= net
->cirseg
->height
;
1007 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1008 cir_width
= (int)round(tempX
);
1009 cir_height
= (int)round(tempY
);
1011 tempX
= net
->cirseg
->cp_x
;
1012 tempY
= net
->cirseg
->cp_y
;
1013 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1014 cp_x
= (int)round(tempX
);
1015 cp_y
= (int)round(tempY
);
1019 * Set GdkFunction depending on if this (gerber) layer is inverted
1020 * and allow for the photoplot being negative.
1022 gdk_gc_set_function(gc
, GDK_COPY
);
1023 if ((net
->layer
->polarity
== GERBV_POLARITY_CLEAR
) != (polarity
== GERBV_POLARITY_NEGATIVE
))
1024 gdk_gc_set_foreground(gc
, &opaque
);
1026 gdk_gc_set_foreground(gc
, &transparent
);
1029 * Polygon Area Fill routines
1031 switch (net
->interpolation
) {
1032 case GERBV_INTERPOLATION_PAREA_START
:
1033 draw_gdk_render_polygon_object (net
,image
,sr_x
,sr_y
,&fullMatrix
,
1034 &scaleMatrix
,gc
,pgc
,pixmap
);
1036 /* make sure we completely skip over any deleted nodes */
1037 case GERBV_INTERPOLATION_DELETED
:
1045 * If aperture state is off we allow use of undefined apertures.
1046 * This happens when gerber files starts, but hasn't decided on
1047 * which aperture to use.
1049 if (image
->aperture
[net
->aperture
] == NULL
) {
1050 /* Commenting this out since it gets emitted every time you click on the screen
1051 if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
1052 GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
1058 * Scale points with window scaling and translate them
1060 tempX
= net
->start_x
+ sr_x
;
1061 tempY
= net
->start_y
+ sr_y
;
1062 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1063 xlong1
= (int)round(tempX
);
1064 ylong1
= (int)round(tempY
);
1066 tempX
= net
->stop_x
+ sr_x
;
1067 tempY
= net
->stop_y
+ sr_y
;
1068 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1069 xlong2
= (int)round(tempX
);
1070 ylong2
= (int)round(tempY
);
1072 /* if the object is way outside our view window, just skip over it in order
1073 to eliminate some GDK clipping problems at high zoom levels */
1074 if ((xlong1
< -10000) && (xlong2
< -10000))
1076 if ((ylong1
< -10000) && (ylong2
< -10000))
1078 if ((xlong1
> 10000) && (xlong2
> 10000))
1080 if ((ylong1
> 10000) && (ylong2
> 10000))
1083 if (xlong1
> G_MAXINT
) x1
= G_MAXINT
;
1084 else if (xlong1
< G_MININT
) x1
= G_MININT
;
1085 else x1
= (int)xlong1
;
1087 if (xlong2
> G_MAXINT
) x2
= G_MAXINT
;
1088 else if (xlong2
< G_MININT
) x2
= G_MININT
;
1089 else x2
= (int)xlong2
;
1091 if (ylong1
> G_MAXINT
) y1
= G_MAXINT
;
1092 else if (ylong1
< G_MININT
) y1
= G_MININT
;
1093 else y1
= (int)ylong1
;
1095 if (ylong2
> G_MAXINT
) y2
= G_MAXINT
;
1096 else if (ylong2
< G_MININT
) y2
= G_MININT
;
1097 else y2
= (int)ylong2
;
1099 switch (net
->aperture_state
) {
1100 case GERBV_APERTURE_STATE_ON
:
1101 tempX
= image
->aperture
[net
->aperture
]->parameter
[0];
1102 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1103 p1
= (int)round(tempX
);
1105 // p1 = (int)round(image->aperture[net->aperture]->parameter[0] * scale);
1106 if (image
->aperture
[net
->aperture
]->type
== GERBV_APTYPE_RECTANGLE
)
1107 gdk_gc_set_line_attributes(gc
, p1
,
1112 gdk_gc_set_line_attributes(gc
, p1
,
1117 switch (net
->interpolation
) {
1118 case GERBV_INTERPOLATION_x10
:
1119 case GERBV_INTERPOLATION_LINEARx01
:
1120 case GERBV_INTERPOLATION_LINEARx001
:
1121 GERB_MESSAGE("Linear != x1\n");
1122 gdk_gc_set_line_attributes(gc
, p1
,
1123 GDK_LINE_ON_OFF_DASH
,
1126 gdk_draw_line(*pixmap
, gc
, x1
, y1
, x2
, y2
);
1127 gdk_gc_set_line_attributes(gc
, p1
,
1132 case GERBV_INTERPOLATION_LINEARx1
:
1133 if (image
->aperture
[net
->aperture
]->type
!= GERBV_APTYPE_RECTANGLE
)
1134 gdk_draw_line(*pixmap
, gc
, x1
, y1
, x2
, y2
);
1139 tempX
= image
->aperture
[net
->aperture
]->parameter
[0]/2;
1140 tempY
= image
->aperture
[net
->aperture
]->parameter
[1]/2;
1141 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1142 dx
= (int)round(tempX
);
1143 dy
= (int)round(tempY
);
1145 if(x1
> x2
) dx
= -dx
;
1146 if(y1
> y2
) dy
= -dy
;
1147 poly
[0].x
= x1
- dx
; poly
[0].y
= y1
- dy
;
1148 poly
[1].x
= x1
- dx
; poly
[1].y
= y1
+ dy
;
1149 poly
[2].x
= x2
- dx
; poly
[2].y
= y2
+ dy
;
1150 poly
[3].x
= x2
+ dx
; poly
[3].y
= y2
+ dy
;
1151 poly
[4].x
= x2
+ dx
; poly
[4].y
= y2
- dy
;
1152 poly
[5].x
= x1
+ dx
; poly
[5].y
= y1
- dy
;
1153 gdk_draw_polygon(*pixmap
, gc
, 1, poly
, 6);
1156 case GERBV_INTERPOLATION_CW_CIRCULAR
:
1157 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
1158 gerbv_gdk_draw_arc(*pixmap
, gc
, cp_x
, cp_y
, cir_width
, cir_height
,
1159 net
->cirseg
->angle1
, net
->cirseg
->angle2
);
1165 case GERBV_APERTURE_STATE_OFF
:
1167 case GERBV_APERTURE_STATE_FLASH
:
1168 tempX
= image
->aperture
[net
->aperture
]->parameter
[0];
1169 tempY
= image
->aperture
[net
->aperture
]->parameter
[1];
1170 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1171 p1
= (int)round(tempX
);
1172 p2
= (int)round(tempY
);
1173 tempX
= image
->aperture
[net
->aperture
]->parameter
[2];
1174 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1175 p3
= (int)round(tempX
);
1177 switch (image
->aperture
[net
->aperture
]->type
) {
1178 case GERBV_APTYPE_CIRCLE
:
1179 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
);
1181 * If circle has an inner diameter we must remove
1182 * that part of the circle to make a hole in it.
1183 * We should actually support square holes too,
1184 * but due to laziness I don't.
1187 gdk_gc_get_values(gc
, &gc_values
);
1188 if (gc_values
.foreground
.pixel
== opaque
.pixel
) {
1189 gdk_gc_set_foreground(gc
, &transparent
);
1190 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p2
);
1191 gdk_gc_set_foreground(gc
, &opaque
);
1193 gdk_gc_set_foreground(gc
, &opaque
);
1194 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p2
);
1195 gdk_gc_set_foreground(gc
, &transparent
);
1200 case GERBV_APTYPE_RECTANGLE
:
1201 gerbv_gdk_draw_rectangle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
, p2
);
1203 case GERBV_APTYPE_OVAL
:
1204 gerbv_gdk_draw_oval(*pixmap
, gc
, TRUE
, x2
, y2
, p1
, p2
);
1206 case GERBV_APTYPE_POLYGON
:
1207 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
);
1209 case GERBV_APTYPE_MACRO
:
1210 gerbv_gdk_draw_amacro(*pixmap
, gc
,
1211 image
->aperture
[net
->aperture
]->simplified
,
1215 GERB_MESSAGE("Unknown aperture type\n");
1220 GERB_MESSAGE("Unknown aperture state\n");
1227 * Destroy GCs before exiting
1234 } /* image2pixmap */