* rework export svg/pdf/ps functionality to export images with 1:1 scale. Previously...
[geda-gerbv.git] / src / draw-gdk.c
blob64df1332abd51e91a38e769b886db13e3a0cdecb
1 /*
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)
7 * $Id$
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
24 /** \file draw-gdk.c
25 \brief GDK rendering functions
26 \ingroup libgerbv
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h> /* ceil(), atan2() */
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
41 #include <gtk/gtk.h>
42 #include "gerbv.h"
43 #include "draw-gdk.h"
45 #undef round
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
59 * angels.
62 static GdkPoint
63 rotate_point(GdkPoint point, int angle)
65 double sint, cost;
66 GdkPoint returned;
68 if (angle == 0)
69 return point;
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);
77 return returned;
82 * Aperture macro primitive 1 (Circle)
84 static void
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;
97 GdkColor color;
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);
104 /* Exposure */
105 if (p[exposure_idx] == 0.0) {
106 color.pixel = 0;
107 gdk_gc_set_foreground(local_gc, &color);
110 gdk_gc_set_line_attributes(local_gc,
111 1, /* outline always 1 pixels */
112 GDK_LINE_SOLID,
113 GDK_CAP_BUTT,
114 GDK_JOIN_MITER);
117 * A filled circle
119 gdk_draw_arc(pixmap, local_gc, 1, real_x, real_y, dia, dia,
120 0, full_circle);
122 gdk_gc_unref(local_gc);
124 return;
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.
133 static void
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;
144 double rotation;
145 GdkPoint *points;
146 GdkColor color;
148 /* Include start point */
149 nuf_points = (int)p[nuf_points_idx] + 1;
150 points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_points);
151 if (!points) {
152 g_free(points);
153 return;
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]);
160 if (rotation != 0.0)
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);
168 /* Exposure */
169 if (p[exposure_idx] == 0.0) {
170 color.pixel = 0;
171 gdk_gc_set_foreground(local_gc, &color);
174 gdk_gc_set_line_attributes(local_gc,
175 1, /* outline always 1 pixels */
176 GDK_LINE_SOLID,
177 GDK_CAP_BUTT,
178 GDK_JOIN_MITER);
179 gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
181 g_free(points);
183 gdk_gc_unref(local_gc);
185 return;
186 } /* gerbv_gdk_draw_prim4 */
190 * Aperture macro primitive 5 (polygon)
192 static void
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;
202 int nuf_vertices, i;
203 double vertex, tick, rotation, radius;
204 GdkPoint *points;
205 GdkGC *local_gc = gdk_gc_new(pixmap);
206 GdkColor color;
208 nuf_vertices = (int)p[nuf_vertices_idx];
209 points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_vertices);
210 if (!points) {
211 g_free(points);
212 return;
215 gdk_gc_copy(local_gc, gc);
217 /* Exposure */
218 if (p[exposure_idx] == 0.0) {
219 color.pixel = 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 +
229 p[center_x_idx];
230 points[i].y = (int)round(scale * radius * sin(vertex)) + y +
231 p[center_y_idx];
234 gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_vertices);
236 gdk_gc_unref(local_gc);
238 g_free(points);
239 return;
240 } /* gerbv_gdk_draw_prim5 */
244 * Doesn't handle and explicit x,y yet
245 * Questions:
246 * - is "gap" distance between edges of circles or distance between
247 * center of line of circle?
249 static void
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);
261 double real_dia;
262 double real_gap;
263 int circle;
264 GdkPoint crosshair[4];
265 int point;
267 gdk_gc_copy(local_gc, gc);
268 gdk_gc_set_line_attributes(local_gc,
269 (int)round(scale * p[ci_thickness_idx]),
270 GDK_LINE_SOLID,
271 GDK_CAP_BUTT,
272 GDK_JOIN_MITER);
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++) {
279 * Non filled 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);
289 * Cross Hair
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]),
303 GDK_LINE_SOLID,
304 GDK_CAP_BUTT,
305 GDK_JOIN_MITER);
307 for (point = 0; point < 4; point++) {
308 crosshair[point] = rotate_point(crosshair[point],
309 p[rotation_idx]);
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);
322 return;
323 } /* gerbv_gdk_draw_prim6 */
326 static void
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;
335 GdkGCValues gc_val;
336 int diameter, i;
337 GdkGC *local_gc = gdk_gc_new(pixmap);
338 GdkPoint point[4];
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),
345 GDK_LINE_SOLID,
346 GDK_CAP_BUTT,
347 GDK_JOIN_MITER);
350 * Non filled circle
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);
357 * Cross hair
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;
365 point[i].y = 0;
366 point[i] = rotate_point(point[i], p[rotation_idx] + 90 * i);
367 point[i].x += x;
368 point[i].y += y;
371 gdk_gc_set_line_attributes(local_gc,
372 (int)round(scale * p[ch_thickness_idx]),
373 GDK_LINE_SOLID,
374 GDK_CAP_BUTT,
375 GDK_JOIN_MITER);
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;
381 else
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);
393 return;
394 } /* gerbv_gdk_draw_prim7 */
398 * Doesn't handle and explicit x,y yet
400 static void
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];
414 GdkColor color;
415 int i;
417 gdk_gc_copy(local_gc, gc);
419 /* Exposure */
420 if (p[exposure_idx] == 0.0) {
421 color.pixel = 0;
422 gdk_gc_set_foreground(local_gc, &color);
425 gdk_gc_set_line_attributes(local_gc,
426 (int)round(scale * p[linewidth_idx]),
427 GDK_LINE_SOLID,
428 GDK_CAP_BUTT,
429 GDK_JOIN_MITER);
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);
448 return;
449 } /* gerbv_gdk_draw_prim20 */
452 static void
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];
464 GdkColor color;
465 GdkGC *local_gc = gdk_gc_new(pixmap);
466 int half_width, half_height;
467 int i;
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);
492 /* Exposure */
493 if (p[exposure_idx] == 0.0) {
494 color.pixel = 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);
502 return;
503 } /* gerbv_gdk_draw_prim21 */
507 * Doesn't handle explicit x,y yet
509 static void
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);
522 GdkColor color;
523 int i;
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])
529 * scale);
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])
533 * scale);
534 points[2].y = (int)round((p[y_lower_left_idx] - p[height_idx])
535 * scale);
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])
539 * scale);
541 for (i = 0; i < nuf_points; i++) {
542 points[i] = rotate_point(points[i], p[rotation_idx]);
543 points[i].x += x;
544 points[i].y += y;
547 gdk_gc_copy(local_gc, gc);
549 /* Exposure */
550 if (p[exposure_idx] == 0.0) {
551 color.pixel = 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);
559 return;
560 } /* gerbv_gdk_draw_prim22 */
563 static void
564 gerbv_gdk_draw_amacro(GdkPixmap *pixmap, GdkGC *gc,
565 gerbv_simplified_amacro_t *s, double scale,
566 gint x, gint y)
568 gerbv_simplified_amacro_t *ls = s;
570 dprintf("Drawing simplified aperture macros:\n");
571 while (ls != NULL) {
573 switch (ls->type) {
574 case GERBV_APTYPE_MACRO_CIRCLE:
575 gerbv_gdk_draw_prim1(pixmap, gc, ls->parameter, scale, x, y);
576 dprintf(" Circle\n");
577 break;
578 case GERBV_APTYPE_MACRO_OUTLINE:
579 gerbv_gdk_draw_prim4(pixmap, gc, ls->parameter, scale, x, y);
580 dprintf(" Outline\n");
581 break;
582 case GERBV_APTYPE_MACRO_POLYGON:
583 gerbv_gdk_draw_prim5(pixmap, gc, ls->parameter, scale, x, y);
584 dprintf(" Polygon\n");
585 break;
586 case GERBV_APTYPE_MACRO_MOIRE:
587 gerbv_gdk_draw_prim6(pixmap, gc, ls->parameter, scale, x, y);
588 dprintf(" Moiré\n");
589 break;
590 case GERBV_APTYPE_MACRO_THERMAL:
591 gerbv_gdk_draw_prim7(pixmap, gc, ls->parameter, scale, x, y);
592 dprintf(" Thermal\n");
593 break;
594 case GERBV_APTYPE_MACRO_LINE20:
595 gerbv_gdk_draw_prim20(pixmap, gc, ls->parameter, scale, x, y);
596 dprintf(" Line 20\n");
597 break;
598 case GERBV_APTYPE_MACRO_LINE21:
599 gerbv_gdk_draw_prim21(pixmap, gc, ls->parameter, scale, x, y);
600 dprintf(" Line 21\n");
601 break;
602 case GERBV_APTYPE_MACRO_LINE22:
603 gerbv_gdk_draw_prim22(pixmap, gc, ls->parameter, scale, x, y);
604 dprintf(" Line 22\n");
605 break;
606 default:
607 GERB_FATAL_ERROR("Unknown simplified aperture macro");
610 ls = ls->next;
613 } /* gerbv_gdk_draw_amacro */
617 * Draws a circle _centered_ at x,y with diameter dia
619 static void
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);
629 return;
630 } /* gerbv_gdk_draw_circle */
634 * Draws a rectangle _centered_ at x,y with sides x_side, y_side
636 static void
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);
646 return;
647 } /* gerbv_gdk_draw_rectangle */
651 * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
653 static void
654 gerbv_gdk_draw_oval(GdkPixmap *pixmap, GdkGC *gc,
655 gint filled, gint x, gint y, gint x_axis, gint y_axis)
657 gint delta = 0;
658 GdkGC *local_gc = gdk_gc_new(pixmap);
660 gdk_gc_copy(local_gc, gc);
662 if (x_axis > y_axis) {
663 /* Draw in x axis */
664 delta = x_axis / 2 - y_axis / 2;
665 gdk_gc_set_line_attributes(local_gc, y_axis,
666 GDK_LINE_SOLID,
667 GDK_CAP_ROUND,
668 GDK_JOIN_MITER);
669 gdk_draw_line(pixmap, local_gc, x - delta, y, x + delta, y);
670 } else {
671 /* Draw in y axis */
672 delta = y_axis / 2 - x_axis / 2;
673 gdk_gc_set_line_attributes(local_gc, x_axis,
674 GDK_LINE_SOLID,
675 GDK_CAP_ROUND,
676 GDK_JOIN_MITER);
677 gdk_draw_line(pixmap, local_gc, x, y - delta, x, y + delta);
680 gdk_gc_unref(local_gc);
682 return;
683 } /* gerbv_gdk_draw_oval */
687 * Draws an arc
688 * Draws an arc _centered_ at x,y
689 * direction: 0 counterclockwise, 1 clockwise
691 static void
692 gerbv_gdk_draw_arc(GdkPixmap *pixmap, GdkGC *gc,
693 int x, int y,
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);
703 return;
704 } /* gerbv_gdk_draw_arc */
706 void
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;
715 int steps,i;
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 */
720 curr_point_idx = 0;
721 pointArraySize = 0;
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;
764 curr_point_idx++;
765 break;
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
769 with GDK */
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);
781 curr_point_idx++;
783 break;
784 case GERBV_INTERPOLATION_PAREA_END :
785 gdk_gc_copy(pgc, gc);
786 gdk_gc_set_line_attributes(pgc, 1,
787 GDK_LINE_SOLID,
788 GDK_CAP_PROJECTING,
789 GDK_JOIN_MITER);
790 gdk_draw_polygon(*pixmap, pgc, 1, points, curr_point_idx);
791 g_free(points);
792 points = NULL;
793 return;
794 default:
795 break;
798 return;
801 void
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);
807 /* apply offset */
808 cairo_matrix_translate (fullMatrix, state->offsetA, state->offsetB);
809 /* apply mirror */
810 switch (state->mirrorState) {
811 case GERBV_MIRROR_STATE_FLIPA:
812 cairo_matrix_scale (fullMatrix, -1, 1);
813 cairo_matrix_scale (scaleMatrix, -1, 1);
814 break;
815 case GERBV_MIRROR_STATE_FLIPB:
816 cairo_matrix_scale (fullMatrix, 1, -1);
817 cairo_matrix_scale (scaleMatrix, -1, 1);
818 break;
819 case GERBV_MIRROR_STATE_FLIPAB:
820 cairo_matrix_scale (fullMatrix, -1, -1);
821 cairo_matrix_scale (scaleMatrix, -1, 1);
822 break;
823 default:
824 break;
826 /* finally, apply axis select */
827 if (state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
828 /* we do this by rotating 270 (counterclockwise, then mirroring
829 the Y axis */
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,
841 gchar drawMode,
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;
851 gint x1, y1, x2, y2;
852 glong xlong1, ylong1, xlong2, ylong2;
853 int p1, p2, p3;
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;
858 gdouble tempX,tempY;
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;
864 else
865 polarity = GERBV_POLARITY_POSITIVE;
866 } else {
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
874 // optimizations
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);
891 /* offset image */
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)
899 scaleY *= -1;
900 if (transform.mirrorAroundY)
901 scaleX *= -1;
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
924 gdk_gc_unref(gc);
925 gdk_gc_unref(pgc);
927 return 0;
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);
941 } else {
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
964 for it */
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) {
976 int i;
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)
983 foundNet = TRUE;
985 if (!foundNet)
986 continue;
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))) {
998 break;
1002 * If circle segment, scale and translate that one too
1004 if (net->cirseg) {
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);
1025 else
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);
1035 continue;
1036 /* make sure we completely skip over any deleted nodes */
1037 case GERBV_INTERPOLATION_DELETED:
1038 continue;
1039 default :
1040 break;
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);
1054 continue;
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))
1075 continue;
1076 if ((ylong1 < -10000) && (ylong2 < -10000))
1077 continue;
1078 if ((xlong1 > 10000) && (xlong2 > 10000))
1079 continue;
1080 if ((ylong1 > 10000) && (ylong2 > 10000))
1081 continue;
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,
1108 GDK_LINE_SOLID,
1109 GDK_CAP_PROJECTING,
1110 GDK_JOIN_MITER);
1111 else
1112 gdk_gc_set_line_attributes(gc, p1,
1113 GDK_LINE_SOLID,
1114 GDK_CAP_ROUND,
1115 GDK_JOIN_MITER);
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,
1124 GDK_CAP_ROUND,
1125 GDK_JOIN_MITER);
1126 gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
1127 gdk_gc_set_line_attributes(gc, p1,
1128 GDK_LINE_SOLID,
1129 GDK_CAP_ROUND,
1130 GDK_JOIN_MITER);
1131 break;
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);
1135 else {
1136 gint dx, dy;
1137 GdkPoint poly[6];
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);
1155 break;
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);
1160 break;
1161 default :
1162 break;
1164 break;
1165 case GERBV_APERTURE_STATE_OFF :
1166 break;
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.
1186 if (p2) {
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);
1192 } else {
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);
1199 break;
1200 case GERBV_APTYPE_RECTANGLE:
1201 gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
1202 break;
1203 case GERBV_APTYPE_OVAL :
1204 gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
1205 break;
1206 case GERBV_APTYPE_POLYGON :
1207 gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
1208 break;
1209 case GERBV_APTYPE_MACRO :
1210 gerbv_gdk_draw_amacro(*pixmap, gc,
1211 image->aperture[net->aperture]->simplified,
1212 scale, x2, y2);
1213 break;
1214 default :
1215 GERB_MESSAGE("Unknown aperture type\n");
1216 return 0;
1218 break;
1219 default :
1220 GERB_MESSAGE("Unknown aperture state\n");
1221 return 0;
1227 * Destroy GCs before exiting
1229 gdk_gc_unref(gc);
1230 gdk_gc_unref(pgc);
1232 return 1;
1234 } /* image2pixmap */