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
);
262 double real_dia_diff
;
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_dia_diff
= 2*(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_dia_diff
* circle
) * scale
;
284 gdk_draw_arc(pixmap
, local_gc
, 0, x
- dia
/ 2, y
- dia
/ 2,
285 dia
, dia
, 0, full_circle
);
292 memset(crosshair
, 0, sizeof(GdkPoint
) * 4);
293 crosshair
[0].x
= (int)((p
[ch_length_idx
] / 2.0) * scale
);
294 /*crosshair[0].y = 0;*/
295 crosshair
[1].x
= -crosshair
[0].x
;
296 /*crosshair[1].y = 0;*/
297 /*crosshair[2].x = 0;*/
298 crosshair
[2].y
= crosshair
[0].x
;
299 /*crosshair[3].x = 0;*/
300 crosshair
[3].y
= -crosshair
[0].x
;
302 gdk_gc_set_line_attributes(local_gc
,
303 (int)round(scale
* p
[ch_thickness_idx
]),
308 for (point
= 0; point
< 4; point
++) {
309 crosshair
[point
] = rotate_point(crosshair
[point
],
311 crosshair
[point
].x
+= x
;
312 crosshair
[point
].y
+= y
;
314 gdk_draw_line(pixmap
, local_gc
,
315 crosshair
[0].x
, crosshair
[0].y
,
316 crosshair
[1].x
, crosshair
[1].y
);
317 gdk_draw_line(pixmap
, local_gc
,
318 crosshair
[2].x
, crosshair
[2].y
,
319 crosshair
[3].x
, crosshair
[3].y
);
321 gdk_gc_unref(local_gc
);
324 } /* gerbv_gdk_draw_prim6 */
328 gerbv_gdk_draw_prim7(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
329 double scale
, gint x
, gint y
)
331 const int outside_dia_idx
= 2;
332 const int inside_dia_idx
= 3;
333 const int ch_thickness_idx
= 4;
334 const int rotation_idx
= 5;
335 const gint full_circle
= 23360;
338 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
340 double ci_thickness
= (p
[outside_dia_idx
] -
341 p
[inside_dia_idx
]) / 2.0;
343 gdk_gc_copy(local_gc
, gc
);
344 gdk_gc_set_line_attributes(local_gc
,
345 (int)round(scale
* ci_thickness
),
353 diameter
= (p
[inside_dia_idx
] + ci_thickness
) * scale
;
354 gdk_draw_arc(pixmap
, local_gc
, 0, x
- diameter
/ 2, y
- diameter
/ 2,
355 diameter
, diameter
, 0, full_circle
);
360 /* Calculate the end points of the crosshair */
361 /* GDK doesn't always remove all of the circle (round of error probably)
362 I extend the crosshair line with 2 (one pixel in each end) to make
363 sure all of the circle is removed with the crosshair */
364 for (i
= 0; i
< 4; i
++) {
365 point
[i
].x
= round((p
[outside_dia_idx
] / 2.0) * scale
) + 2;
367 point
[i
] = rotate_point(point
[i
], p
[rotation_idx
] + 90 * i
);
372 gdk_gc_set_line_attributes(local_gc
,
373 (int)round(scale
* p
[ch_thickness_idx
]),
378 /* The cross hair should "cut out" parts of the circle, hence inverse */
379 gdk_gc_get_values(local_gc
, &gc_val
);
380 if (gc_val
.foreground
.pixel
== 1)
381 gc_val
.foreground
.pixel
= 0;
383 gc_val
.foreground
.pixel
= 1;
384 gdk_gc_set_foreground(local_gc
, &(gc_val
.foreground
));
386 /* Draw the actual cross */
387 gdk_draw_line(pixmap
, local_gc
,
388 point
[0].x
, point
[0].y
, point
[2].x
, point
[2].y
);
389 gdk_draw_line(pixmap
, local_gc
,
390 point
[1].x
, point
[1].y
, point
[3].x
, point
[3].y
);
392 gdk_gc_unref(local_gc
);
395 } /* gerbv_gdk_draw_prim7 */
399 * Doesn't handle and explicit x,y yet
402 gerbv_gdk_draw_prim20(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
403 double scale
, gint x
, gint y
)
405 const int exposure_idx
= 0;
406 const int linewidth_idx
= 1;
407 const int start_x_idx
= 2;
408 const int start_y_idx
= 3;
409 const int end_x_idx
= 4;
410 const int end_y_idx
= 5;
411 const int rotation_idx
= 6;
412 const int nuf_points
= 2;
413 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
414 GdkPoint points
[nuf_points
];
418 gdk_gc_copy(local_gc
, gc
);
421 if (p
[exposure_idx
] == 0.0) {
423 gdk_gc_set_foreground(local_gc
, &color
);
426 gdk_gc_set_line_attributes(local_gc
,
427 (int)round(scale
* p
[linewidth_idx
]),
432 points
[0].x
= (p
[start_x_idx
] * scale
);
433 points
[0].y
= (p
[start_y_idx
] * scale
);
434 points
[1].x
= (p
[end_x_idx
] * scale
);
435 points
[1].y
= (p
[end_y_idx
] * scale
);
437 for (i
= 0; i
< nuf_points
; i
++) {
438 points
[i
] = rotate_point(points
[i
], -p
[rotation_idx
]);
439 points
[i
].x
= x
+ points
[i
].x
;
440 points
[i
].y
= y
- points
[i
].y
;
443 gdk_draw_line(pixmap
, local_gc
,
444 points
[0].x
, points
[0].y
,
445 points
[1].x
, points
[1].y
);
447 gdk_gc_unref(local_gc
);
450 } /* gerbv_gdk_draw_prim20 */
454 gerbv_gdk_draw_prim21(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
455 double scale
, gint x
, gint y
)
457 const int exposure_idx
= 0;
458 const int width_idx
= 1;
459 const int height_idx
= 2;
460 const int exp_x_idx
= 3;
461 const int exp_y_idx
= 4;
462 const int rotation_idx
= 5;
463 const int nuf_points
= 4;
464 GdkPoint points
[nuf_points
];
466 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
467 int half_width
, half_height
;
470 half_width
= (int)round(p
[width_idx
] * scale
/ 2.0);
471 half_height
=(int)round(p
[height_idx
] * scale
/ 2.0);
473 points
[0].x
= half_width
;
474 points
[0].y
= half_height
;
476 points
[1].x
= half_width
;
477 points
[1].y
= -half_height
;
479 points
[2].x
= -half_width
;
480 points
[2].y
= -half_height
;
482 points
[3].x
= -half_width
;
483 points
[3].y
= half_height
;
485 for (i
= 0; i
< nuf_points
; i
++) {
486 points
[i
] = rotate_point(points
[i
], p
[rotation_idx
]);
487 points
[i
].x
+= (x
+ (int)(p
[exp_x_idx
] * scale
));
488 points
[i
].y
+= (y
- (int)(p
[exp_y_idx
] * scale
));
491 gdk_gc_copy(local_gc
, gc
);
494 if (p
[exposure_idx
] == 0.0) {
496 gdk_gc_set_foreground(local_gc
, &color
);
499 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_points
);
501 gdk_gc_unref(local_gc
);
504 } /* gerbv_gdk_draw_prim21 */
508 * Doesn't handle explicit x,y yet
511 gerbv_gdk_draw_prim22(GdkPixmap
*pixmap
, GdkGC
*gc
, double *p
,
512 double scale
, gint x
, gint y
)
514 const int exposure_idx
= 0;
515 const int width_idx
= 1;
516 const int height_idx
= 2;
517 const int x_lower_left_idx
= 3;
518 const int y_lower_left_idx
= 4;
519 const int rotation_idx
= 5;
520 const int nuf_points
= 4;
521 GdkPoint points
[nuf_points
];
522 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
526 points
[0].x
= (int)round(p
[x_lower_left_idx
] * scale
);
527 points
[0].y
= (int)round(p
[y_lower_left_idx
] * scale
);
529 points
[1].x
= (int)round((p
[x_lower_left_idx
] + p
[width_idx
])
531 points
[1].y
= (int)round(p
[y_lower_left_idx
] * scale
);
533 points
[2].x
= (int)round((p
[x_lower_left_idx
] + p
[width_idx
])
535 points
[2].y
= (int)round((p
[y_lower_left_idx
] + p
[height_idx
])
538 points
[3].x
= (int)round(p
[x_lower_left_idx
] * scale
);
539 points
[3].y
= (int)round((p
[y_lower_left_idx
] + p
[height_idx
])
542 for (i
= 0; i
< nuf_points
; i
++) {
543 points
[i
] = rotate_point(points
[i
], p
[rotation_idx
]);
544 points
[i
].x
= x
+ points
[i
].x
;
545 points
[i
].y
= y
- points
[i
].y
;
548 gdk_gc_copy(local_gc
, gc
);
551 if (p
[exposure_idx
] == 0.0) {
553 gdk_gc_set_foreground(local_gc
, &color
);
556 gdk_draw_polygon(pixmap
, local_gc
, 1, points
, nuf_points
);
558 gdk_gc_unref(local_gc
);
561 } /* gerbv_gdk_draw_prim22 */
565 gerbv_gdk_draw_amacro(GdkPixmap
*pixmap
, GdkGC
*gc
,
566 gerbv_simplified_amacro_t
*s
, double scale
,
569 gerbv_simplified_amacro_t
*ls
= s
;
571 dprintf("Drawing simplified aperture macros:\n");
575 case GERBV_APTYPE_MACRO_CIRCLE
:
576 gerbv_gdk_draw_prim1(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
577 dprintf(" Circle\n");
579 case GERBV_APTYPE_MACRO_OUTLINE
:
580 gerbv_gdk_draw_prim4(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
581 dprintf(" Outline\n");
583 case GERBV_APTYPE_MACRO_POLYGON
:
584 gerbv_gdk_draw_prim5(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
585 dprintf(" Polygon\n");
587 case GERBV_APTYPE_MACRO_MOIRE
:
588 gerbv_gdk_draw_prim6(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
589 dprintf(" Moiré\n");
591 case GERBV_APTYPE_MACRO_THERMAL
:
592 gerbv_gdk_draw_prim7(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
593 dprintf(" Thermal\n");
595 case GERBV_APTYPE_MACRO_LINE20
:
596 gerbv_gdk_draw_prim20(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
597 dprintf(" Line 20\n");
599 case GERBV_APTYPE_MACRO_LINE21
:
600 gerbv_gdk_draw_prim21(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
601 dprintf(" Line 21\n");
603 case GERBV_APTYPE_MACRO_LINE22
:
604 gerbv_gdk_draw_prim22(pixmap
, gc
, ls
->parameter
, scale
, x
, y
);
605 dprintf(" Line 22\n");
608 GERB_FATAL_ERROR("Unknown simplified aperture macro");
614 } /* gerbv_gdk_draw_amacro */
618 * Draws a circle _centered_ at x,y with diameter dia
621 gerbv_gdk_draw_circle(GdkPixmap
*pixmap
, GdkGC
*gc
,
622 gint filled
, gint x
, gint y
, gint dia
)
624 static const gint full_circle
= 23360;
625 gint real_x
= x
- dia
/ 2;
626 gint real_y
= y
- dia
/ 2;
628 gdk_draw_arc(pixmap
, gc
, filled
, real_x
, real_y
, dia
, dia
, 0, full_circle
);
631 } /* gerbv_gdk_draw_circle */
635 * Draws a rectangle _centered_ at x,y with sides x_side, y_side
638 gerbv_gdk_draw_rectangle(GdkPixmap
*pixmap
, GdkGC
*gc
,
639 gint filled
, gint x
, gint y
, gint x_side
, gint y_side
)
642 gint real_x
= x
- x_side
/ 2;
643 gint real_y
= y
- y_side
/ 2;
645 gdk_draw_rectangle(pixmap
, gc
, filled
, real_x
, real_y
, x_side
, y_side
);
648 } /* gerbv_gdk_draw_rectangle */
652 * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
655 gerbv_gdk_draw_oval(GdkPixmap
*pixmap
, GdkGC
*gc
,
656 gint filled
, gint x
, gint y
, gint x_axis
, gint y_axis
)
659 GdkGC
*local_gc
= gdk_gc_new(pixmap
);
661 gdk_gc_copy(local_gc
, gc
);
663 if (x_axis
> y_axis
) {
665 delta
= x_axis
/ 2 - y_axis
/ 2;
666 gdk_gc_set_line_attributes(local_gc
, y_axis
,
670 gdk_draw_line(pixmap
, local_gc
, x
- delta
, y
, x
+ delta
, y
);
673 delta
= y_axis
/ 2 - x_axis
/ 2;
674 gdk_gc_set_line_attributes(local_gc
, x_axis
,
678 gdk_draw_line(pixmap
, local_gc
, x
, y
- delta
, x
, y
+ delta
);
681 gdk_gc_unref(local_gc
);
684 } /* gerbv_gdk_draw_oval */
689 * Draws an arc _centered_ at x,y
690 * direction: 0 counterclockwise, 1 clockwise
693 gerbv_gdk_draw_arc(GdkPixmap
*pixmap
, GdkGC
*gc
,
695 int width
, int height
,
696 double angle1
, double angle2
)
698 gint real_x
= x
- width
/ 2;
699 gint real_y
= y
- height
/ 2;
701 gdk_draw_arc(pixmap
, gc
, FALSE
, real_x
, real_y
, width
, height
,
702 (gint
)(angle1
* 64.0), (gint
)(((angle2
- angle1
) * 64.0)));
705 } /* gerbv_gdk_draw_arc */
708 draw_gdk_render_polygon_object (gerbv_net_t
*oldNet
, gerbv_image_t
*image
, double sr_x
, double sr_y
,
709 cairo_matrix_t
*fullMatrix
, cairo_matrix_t
*scaleMatrix
, GdkGC
*gc
, GdkGC
*pgc
,
710 GdkPixmap
**pixmap
) {
711 gerbv_net_t
*currentNet
;
712 gint x2
,y2
,cp_x
=0,cp_y
=0,cir_width
=0;
713 GdkPoint
*points
= NULL
;
714 int pointArraySize
=0;
715 int curr_point_idx
= 0;
717 gdouble angleDiff
, tempX
, tempY
;
719 /* save the first net in the polygon as the "ID" net pointer
720 in case we are saving this net to the selection array */
724 for (currentNet
= oldNet
->next
; currentNet
!=NULL
; currentNet
= currentNet
->next
){
725 tempX
= currentNet
->stop_x
+ sr_x
;
726 tempY
= currentNet
->stop_y
+ sr_y
;
727 cairo_matrix_transform_point (fullMatrix
, &tempX
, &tempY
);
728 x2
= (int)round(tempX
);
729 y2
= (int)round(tempY
);
732 * If circle segment, scale and translate that one too
734 if (currentNet
->cirseg
) {
735 tempX
= currentNet
->cirseg
->width
;
736 tempY
= currentNet
->cirseg
->height
;
737 cairo_matrix_transform_point (scaleMatrix
, &tempX
, &tempY
);
738 cir_width
= (int)round(tempX
);
740 tempX
= currentNet
->cirseg
->cp_x
+ sr_x
;
741 tempY
= currentNet
->cirseg
->cp_y
+ sr_y
;
742 cairo_matrix_transform_point (fullMatrix
, &tempX
, &tempY
);
743 cp_x
= (int)round(tempX
);
744 cp_y
= (int)round(tempY
);
747 switch (currentNet
->interpolation
) {
748 case GERBV_INTERPOLATION_x10
:
749 case GERBV_INTERPOLATION_LINEARx01
:
750 case GERBV_INTERPOLATION_LINEARx001
:
751 case GERBV_INTERPOLATION_LINEARx1
:
752 if (pointArraySize
< (curr_point_idx
+ 1)) {
753 points
= (GdkPoint
*)g_realloc(points
,sizeof(GdkPoint
) * (curr_point_idx
+ 1));
754 pointArraySize
= (curr_point_idx
+ 1);
756 points
[curr_point_idx
].x
= x2
;
757 points
[curr_point_idx
].y
= y2
;
760 case GERBV_INTERPOLATION_CW_CIRCULAR
:
761 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
762 /* we need to chop up the arc into small lines for rendering
764 angleDiff
= currentNet
->cirseg
->angle2
- currentNet
->cirseg
->angle1
;
765 steps
= (int) abs(angleDiff
);
766 if (pointArraySize
< (curr_point_idx
+ steps
)) {
767 points
= (GdkPoint
*)g_realloc(points
,sizeof(GdkPoint
) * (curr_point_idx
+ steps
));
768 pointArraySize
= (curr_point_idx
+ steps
);
770 for (i
=0; i
<steps
; i
++){
771 points
[curr_point_idx
].x
= cp_x
+ cir_width
/ 2.0 * cos ((currentNet
->cirseg
->angle1
+
772 (angleDiff
* i
) / steps
)*M_PI
/180);
773 points
[curr_point_idx
].y
= cp_y
- cir_width
/ 2.0 * sin ((currentNet
->cirseg
->angle1
+
774 (angleDiff
* i
) / steps
)*M_PI
/180);
778 case GERBV_INTERPOLATION_PAREA_END
:
779 gdk_gc_copy(pgc
, gc
);
780 gdk_gc_set_line_attributes(pgc
, 1,
784 gdk_draw_polygon(*pixmap
, pgc
, 1, points
, curr_point_idx
);
796 draw_gdk_apply_netstate_transformation (cairo_matrix_t
*fullMatrix
, cairo_matrix_t
*scaleMatrix
,
797 gerbv_netstate_t
*state
) {
798 /* apply scale factor */
799 cairo_matrix_scale (fullMatrix
, state
->scaleA
, state
->scaleB
);
800 cairo_matrix_scale (scaleMatrix
, state
->scaleA
, state
->scaleB
);
802 cairo_matrix_translate (fullMatrix
, state
->offsetA
, state
->offsetB
);
804 switch (state
->mirrorState
) {
805 case GERBV_MIRROR_STATE_FLIPA
:
806 cairo_matrix_scale (fullMatrix
, -1, 1);
807 cairo_matrix_scale (scaleMatrix
, -1, 1);
809 case GERBV_MIRROR_STATE_FLIPB
:
810 cairo_matrix_scale (fullMatrix
, 1, -1);
811 cairo_matrix_scale (scaleMatrix
, -1, 1);
813 case GERBV_MIRROR_STATE_FLIPAB
:
814 cairo_matrix_scale (fullMatrix
, -1, -1);
815 cairo_matrix_scale (scaleMatrix
, -1, 1);
820 /* finally, apply axis select */
821 if (state
->axisSelect
== GERBV_AXIS_SELECT_SWAPAB
) {
822 /* we do this by rotating 270 (counterclockwise, then mirroring
824 cairo_matrix_rotate (fullMatrix
, 3 * M_PI
/ 2);
825 cairo_matrix_scale (fullMatrix
, 1, -1);
830 * Convert a gerber image to a GDK clip mask to be used when creating pixmap
833 draw_gdk_image_to_pixmap(GdkPixmap
**pixmap
, gerbv_image_t
*image
,
834 double scale
, double trans_x
, double trans_y
,
836 gerbv_selection_info_t
*selectionInfo
, gerbv_render_info_t
*renderInfo
,
837 gerbv_user_transformation_t transform
)
839 GdkGC
*gc
= gdk_gc_new(*pixmap
);
840 GdkGC
*pgc
= gdk_gc_new(*pixmap
);
841 GdkGCValues gc_values
;
842 struct gerbv_net
*net
;
843 gerbv_netstate_t
*oldState
;
844 gerbv_layer_t
*oldLayer
;
846 glong xlong1
, ylong1
, xlong2
, ylong2
;
848 int cir_width
= 0, cir_height
= 0;
849 int cp_x
= 0, cp_y
= 0;
850 GdkColor transparent
, opaque
;
851 gerbv_polarity_t polarity
;
853 gdouble minX
=0,minY
=0,maxX
=0,maxY
=0;
855 if (transform
.inverted
) {
856 if (image
->info
->polarity
== GERBV_POLARITY_POSITIVE
)
857 polarity
= GERBV_POLARITY_NEGATIVE
;
859 polarity
= GERBV_POLARITY_POSITIVE
;
861 polarity
= image
->info
->polarity
;
863 if (drawMode
== DRAW_SELECTIONS
)
864 polarity
= GERBV_POLARITY_POSITIVE
;
866 gboolean useOptimizations
= TRUE
;
867 // if the user is using any transformations for this layer, then don't bother using rendering
869 if ((fabs(transform
.translateX
) > 0.00001) ||
870 (fabs(transform
.translateY
) > 0.00001) ||
871 (fabs(transform
.scaleX
- 1) > 0.00001) ||
872 (fabs(transform
.scaleY
- 1) > 0.00001) ||
873 (fabs(transform
.rotation
) > 0.00001) ||
874 transform
.mirrorAroundX
|| transform
.mirrorAroundY
)
875 useOptimizations
= FALSE
;
877 // calculate the transformation matrix for the user_transformation options
878 cairo_matrix_t fullMatrix
, scaleMatrix
;
879 cairo_matrix_init (&fullMatrix
, 1, 0, 0, 1, 0, 0);
880 cairo_matrix_init (&scaleMatrix
, 1, 0, 0, 1, 0, 0);
882 cairo_matrix_translate (&fullMatrix
, trans_x
, trans_y
);
883 cairo_matrix_scale (&fullMatrix
, scale
, scale
);
884 cairo_matrix_scale (&scaleMatrix
, scale
, scale
);
887 cairo_matrix_translate (&fullMatrix
, transform
.translateX
, -1*transform
.translateY
);
888 // don't use mirroring for the scale matrix
889 gdouble scaleX
= transform
.scaleX
;
890 gdouble scaleY
= -1*transform
.scaleY
;
891 cairo_matrix_scale (&scaleMatrix
, scaleX
, -1*scaleY
);
892 if (transform
.mirrorAroundX
)
894 if (transform
.mirrorAroundY
)
897 cairo_matrix_scale (&fullMatrix
, scaleX
, scaleY
);
898 /* do image rotation */
899 cairo_matrix_rotate (&fullMatrix
, transform
.rotation
);
900 //cairo_matrix_rotate (&scaleMatrix, transform.rotation);
902 /* do image rotation */
903 cairo_matrix_rotate (&fullMatrix
, image
->info
->imageRotation
);
905 if (useOptimizations
) {
906 minX
= renderInfo
->lowerLeftX
;
907 minY
= renderInfo
->lowerLeftY
;
908 maxX
= renderInfo
->lowerLeftX
+ (renderInfo
->displayWidth
/
909 renderInfo
->scaleFactorX
);
910 maxY
= renderInfo
->lowerLeftY
+ (renderInfo
->displayHeight
/
911 renderInfo
->scaleFactorY
);
914 if (image
== NULL
|| image
->netlist
== NULL
) {
916 * Destroy GCs before exiting
924 /* Set up the two "colors" we have */
925 opaque
.pixel
= 0; /* opaque will not let color through */
926 transparent
.pixel
= 1; /* transparent will let color through */
929 * Clear clipmask and set draw color depending image on image polarity
931 if (polarity
== GERBV_POLARITY_NEGATIVE
) {
932 gdk_gc_set_foreground(gc
, &transparent
);
933 gdk_draw_rectangle(*pixmap
, gc
, TRUE
, 0, 0, -1, -1);
934 gdk_gc_set_foreground(gc
, &opaque
);
936 gdk_gc_set_foreground(gc
, &opaque
);
937 gdk_draw_rectangle(*pixmap
, gc
, TRUE
, 0, 0, -1, -1);
938 gdk_gc_set_foreground(gc
, &transparent
);
940 oldLayer
= image
->layers
;
941 oldState
= image
->states
;
942 for (net
= image
->netlist
->next
; net
!= NULL
; net
= gerbv_image_return_next_renderable_object(net
)) {
943 int repeat_X
=1, repeat_Y
=1;
944 double repeat_dist_X
=0.0, repeat_dist_Y
=0.0;
945 int repeat_i
, repeat_j
;
948 * If step_and_repeat (%SR%) used, repeat the drawing;
950 repeat_X
= net
->layer
->stepAndRepeat
.X
;
951 repeat_Y
= net
->layer
->stepAndRepeat
.Y
;
952 repeat_dist_X
= net
->layer
->stepAndRepeat
.dist_X
;
953 repeat_dist_Y
= net
->layer
->stepAndRepeat
.dist_Y
;
955 /* check if this is a new netstate */
956 if (net
->state
!= oldState
){
957 /* it's a new state, so recalculate the new transformation matrix
959 draw_gdk_apply_netstate_transformation (&fullMatrix
, &scaleMatrix
, net
->state
);
960 oldState
= net
->state
;
962 /* check if this is a new layer */
963 /* for now, only do layer rotations in GDK rendering */
964 if (net
->layer
!= oldLayer
){
965 cairo_matrix_rotate (&fullMatrix
, net
->layer
->rotation
);
966 oldLayer
= net
->layer
;
969 if (drawMode
== DRAW_SELECTIONS
) {
971 gboolean foundNet
= FALSE
;
973 for (i
=0; i
<selectionInfo
->selectedNodeArray
->len
; i
++){
974 gerbv_selection_item_t sItem
= g_array_index (selectionInfo
->selectedNodeArray
,
975 gerbv_selection_item_t
, i
);
976 if (sItem
.net
== net
)
983 for(repeat_i
= 0; repeat_i
< repeat_X
; repeat_i
++) {
984 for(repeat_j
= 0; repeat_j
< repeat_Y
; repeat_j
++) {
985 double sr_x
= repeat_i
* repeat_dist_X
;
986 double sr_y
= repeat_j
* repeat_dist_Y
;
988 if ((useOptimizations
)&&((net
->boundingBox
.right
+sr_x
< minX
)
989 || (net
->boundingBox
.left
+sr_x
> maxX
)
990 || (net
->boundingBox
.top
+sr_y
< minY
)
991 || (net
->boundingBox
.bottom
+sr_y
> maxY
))) {
996 * If circle segment, scale and translate that one too
999 tempX
= net
->cirseg
->width
;
1000 tempY
= net
->cirseg
->height
;
1001 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1002 cir_width
= (int)round(tempX
);
1003 cir_height
= (int)round(tempY
);
1005 tempX
= net
->cirseg
->cp_x
;
1006 tempY
= net
->cirseg
->cp_y
;
1007 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1008 cp_x
= (int)round(tempX
);
1009 cp_y
= (int)round(tempY
);
1013 * Set GdkFunction depending on if this (gerber) layer is inverted
1014 * and allow for the photoplot being negative.
1016 gdk_gc_set_function(gc
, GDK_COPY
);
1017 if ((net
->layer
->polarity
== GERBV_POLARITY_CLEAR
) != (polarity
== GERBV_POLARITY_NEGATIVE
))
1018 gdk_gc_set_foreground(gc
, &opaque
);
1020 gdk_gc_set_foreground(gc
, &transparent
);
1023 * Polygon Area Fill routines
1025 switch (net
->interpolation
) {
1026 case GERBV_INTERPOLATION_PAREA_START
:
1027 draw_gdk_render_polygon_object (net
,image
,sr_x
,sr_y
,&fullMatrix
,
1028 &scaleMatrix
,gc
,pgc
,pixmap
);
1030 /* make sure we completely skip over any deleted nodes */
1031 case GERBV_INTERPOLATION_DELETED
:
1039 * If aperture state is off we allow use of undefined apertures.
1040 * This happens when gerber files starts, but hasn't decided on
1041 * which aperture to use.
1043 if (image
->aperture
[net
->aperture
] == NULL
) {
1044 /* Commenting this out since it gets emitted every time you click on the screen
1045 if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
1046 GERB_MESSAGE("Aperture D%d is not defined\n", net->aperture);
1052 * Scale points with window scaling and translate them
1054 tempX
= net
->start_x
+ sr_x
;
1055 tempY
= net
->start_y
+ sr_y
;
1056 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1057 xlong1
= (int)round(tempX
);
1058 ylong1
= (int)round(tempY
);
1060 tempX
= net
->stop_x
+ sr_x
;
1061 tempY
= net
->stop_y
+ sr_y
;
1062 cairo_matrix_transform_point (&fullMatrix
, &tempX
, &tempY
);
1063 xlong2
= (int)round(tempX
);
1064 ylong2
= (int)round(tempY
);
1066 /* if the object is way outside our view window, just skip over it in order
1067 to eliminate some GDK clipping problems at high zoom levels */
1068 if ((xlong1
< -10000) && (xlong2
< -10000))
1070 if ((ylong1
< -10000) && (ylong2
< -10000))
1072 if ((xlong1
> 10000) && (xlong2
> 10000))
1074 if ((ylong1
> 10000) && (ylong2
> 10000))
1077 if (xlong1
> G_MAXINT
) x1
= G_MAXINT
;
1078 else if (xlong1
< G_MININT
) x1
= G_MININT
;
1079 else x1
= (int)xlong1
;
1081 if (xlong2
> G_MAXINT
) x2
= G_MAXINT
;
1082 else if (xlong2
< G_MININT
) x2
= G_MININT
;
1083 else x2
= (int)xlong2
;
1085 if (ylong1
> G_MAXINT
) y1
= G_MAXINT
;
1086 else if (ylong1
< G_MININT
) y1
= G_MININT
;
1087 else y1
= (int)ylong1
;
1089 if (ylong2
> G_MAXINT
) y2
= G_MAXINT
;
1090 else if (ylong2
< G_MININT
) y2
= G_MININT
;
1091 else y2
= (int)ylong2
;
1093 switch (net
->aperture_state
) {
1094 case GERBV_APERTURE_STATE_ON
:
1095 tempX
= image
->aperture
[net
->aperture
]->parameter
[0];
1096 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1097 p1
= (int)round(tempX
);
1099 // p1 = (int)round(image->aperture[net->aperture]->parameter[0] * scale);
1100 if (image
->aperture
[net
->aperture
]->type
== GERBV_APTYPE_RECTANGLE
)
1101 gdk_gc_set_line_attributes(gc
, p1
,
1106 gdk_gc_set_line_attributes(gc
, p1
,
1111 switch (net
->interpolation
) {
1112 case GERBV_INTERPOLATION_x10
:
1113 case GERBV_INTERPOLATION_LINEARx01
:
1114 case GERBV_INTERPOLATION_LINEARx001
:
1115 GERB_MESSAGE("Linear != x1\n");
1116 gdk_gc_set_line_attributes(gc
, p1
,
1117 GDK_LINE_ON_OFF_DASH
,
1120 gdk_draw_line(*pixmap
, gc
, x1
, y1
, x2
, y2
);
1121 gdk_gc_set_line_attributes(gc
, p1
,
1126 case GERBV_INTERPOLATION_LINEARx1
:
1127 if (image
->aperture
[net
->aperture
]->type
!= GERBV_APTYPE_RECTANGLE
)
1128 gdk_draw_line(*pixmap
, gc
, x1
, y1
, x2
, y2
);
1133 tempX
= image
->aperture
[net
->aperture
]->parameter
[0]/2;
1134 tempY
= image
->aperture
[net
->aperture
]->parameter
[1]/2;
1135 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1136 dx
= (int)round(tempX
);
1137 dy
= (int)round(tempY
);
1139 if(x1
> x2
) dx
= -dx
;
1140 if(y1
> y2
) dy
= -dy
;
1141 poly
[0].x
= x1
- dx
; poly
[0].y
= y1
- dy
;
1142 poly
[1].x
= x1
- dx
; poly
[1].y
= y1
+ dy
;
1143 poly
[2].x
= x2
- dx
; poly
[2].y
= y2
+ dy
;
1144 poly
[3].x
= x2
+ dx
; poly
[3].y
= y2
+ dy
;
1145 poly
[4].x
= x2
+ dx
; poly
[4].y
= y2
- dy
;
1146 poly
[5].x
= x1
+ dx
; poly
[5].y
= y1
- dy
;
1147 gdk_draw_polygon(*pixmap
, gc
, 1, poly
, 6);
1150 case GERBV_INTERPOLATION_CW_CIRCULAR
:
1151 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
1152 gerbv_gdk_draw_arc(*pixmap
, gc
, cp_x
, cp_y
, cir_width
, cir_height
,
1153 net
->cirseg
->angle1
, net
->cirseg
->angle2
);
1159 case GERBV_APERTURE_STATE_OFF
:
1161 case GERBV_APERTURE_STATE_FLASH
:
1162 tempX
= image
->aperture
[net
->aperture
]->parameter
[0];
1163 tempY
= image
->aperture
[net
->aperture
]->parameter
[1];
1164 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1165 p1
= (int)round(tempX
);
1166 p2
= (int)round(tempY
);
1167 tempX
= image
->aperture
[net
->aperture
]->parameter
[2];
1168 cairo_matrix_transform_point (&scaleMatrix
, &tempX
, &tempY
);
1170 switch (image
->aperture
[net
->aperture
]->type
) {
1171 case GERBV_APTYPE_CIRCLE
:
1172 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
);
1174 * If circle has an inner diameter we must remove
1175 * that part of the circle to make a hole in it.
1176 * We should actually support square holes too,
1177 * but due to laziness I don't.
1180 gdk_gc_get_values(gc
, &gc_values
);
1181 if (gc_values
.foreground
.pixel
== opaque
.pixel
) {
1182 gdk_gc_set_foreground(gc
, &transparent
);
1183 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p2
);
1184 gdk_gc_set_foreground(gc
, &opaque
);
1186 gdk_gc_set_foreground(gc
, &opaque
);
1187 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p2
);
1188 gdk_gc_set_foreground(gc
, &transparent
);
1193 case GERBV_APTYPE_RECTANGLE
:
1194 gerbv_gdk_draw_rectangle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
, p2
);
1196 case GERBV_APTYPE_OVAL
:
1197 gerbv_gdk_draw_oval(*pixmap
, gc
, TRUE
, x2
, y2
, p1
, p2
);
1199 case GERBV_APTYPE_POLYGON
:
1200 gerbv_gdk_draw_circle(*pixmap
, gc
, TRUE
, x2
, y2
, p1
);
1202 case GERBV_APTYPE_MACRO
:
1203 gerbv_gdk_draw_amacro(*pixmap
, gc
,
1204 image
->aperture
[net
->aperture
]->simplified
,
1208 GERB_MESSAGE("Unknown aperture type\n");
1213 GERB_MESSAGE("Unknown aperture state\n");
1220 * Destroy GCs before exiting
1227 } /* image2pixmap */