fix rendering algorithm for MOIRE macro (reported by Matthias on mailing list)
[geda-gerbv.git] / src / draw-gdk.c
blob28cab57b85a2898334aaf186c24fa1f3c8fd5677
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_dia_diff;
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_dia_diff = 2*(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_dia_diff * circle) * scale;
283 if (dia >= 0){
284 gdk_draw_arc(pixmap, local_gc, 0, x - dia / 2, y - dia / 2,
285 dia, dia, 0, full_circle);
290 * Cross Hair
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]),
304 GDK_LINE_SOLID,
305 GDK_CAP_BUTT,
306 GDK_JOIN_MITER);
308 for (point = 0; point < 4; point++) {
309 crosshair[point] = rotate_point(crosshair[point],
310 p[rotation_idx]);
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);
323 return;
324 } /* gerbv_gdk_draw_prim6 */
327 static void
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;
336 GdkGCValues gc_val;
337 int diameter, i;
338 GdkGC *local_gc = gdk_gc_new(pixmap);
339 GdkPoint point[4];
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),
346 GDK_LINE_SOLID,
347 GDK_CAP_BUTT,
348 GDK_JOIN_MITER);
351 * Non filled circle
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);
358 * Cross hair
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;
366 point[i].y = 0;
367 point[i] = rotate_point(point[i], p[rotation_idx] + 90 * i);
368 point[i].x += x;
369 point[i].y += y;
372 gdk_gc_set_line_attributes(local_gc,
373 (int)round(scale * p[ch_thickness_idx]),
374 GDK_LINE_SOLID,
375 GDK_CAP_BUTT,
376 GDK_JOIN_MITER);
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;
382 else
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);
394 return;
395 } /* gerbv_gdk_draw_prim7 */
399 * Doesn't handle and explicit x,y yet
401 static void
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];
415 GdkColor color;
416 int i;
418 gdk_gc_copy(local_gc, gc);
420 /* Exposure */
421 if (p[exposure_idx] == 0.0) {
422 color.pixel = 0;
423 gdk_gc_set_foreground(local_gc, &color);
426 gdk_gc_set_line_attributes(local_gc,
427 (int)round(scale * p[linewidth_idx]),
428 GDK_LINE_SOLID,
429 GDK_CAP_BUTT,
430 GDK_JOIN_MITER);
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);
449 return;
450 } /* gerbv_gdk_draw_prim20 */
453 static void
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];
465 GdkColor color;
466 GdkGC *local_gc = gdk_gc_new(pixmap);
467 int half_width, half_height;
468 int i;
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);
493 /* Exposure */
494 if (p[exposure_idx] == 0.0) {
495 color.pixel = 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);
503 return;
504 } /* gerbv_gdk_draw_prim21 */
508 * Doesn't handle explicit x,y yet
510 static void
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);
523 GdkColor color;
524 int i;
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])
530 * scale);
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])
534 * scale);
535 points[2].y = (int)round((p[y_lower_left_idx] + p[height_idx])
536 * scale);
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])
540 * scale);
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);
550 /* Exposure */
551 if (p[exposure_idx] == 0.0) {
552 color.pixel = 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);
560 return;
561 } /* gerbv_gdk_draw_prim22 */
564 static void
565 gerbv_gdk_draw_amacro(GdkPixmap *pixmap, GdkGC *gc,
566 gerbv_simplified_amacro_t *s, double scale,
567 gint x, gint y)
569 gerbv_simplified_amacro_t *ls = s;
571 dprintf("Drawing simplified aperture macros:\n");
572 while (ls != NULL) {
574 switch (ls->type) {
575 case GERBV_APTYPE_MACRO_CIRCLE:
576 gerbv_gdk_draw_prim1(pixmap, gc, ls->parameter, scale, x, y);
577 dprintf(" Circle\n");
578 break;
579 case GERBV_APTYPE_MACRO_OUTLINE:
580 gerbv_gdk_draw_prim4(pixmap, gc, ls->parameter, scale, x, y);
581 dprintf(" Outline\n");
582 break;
583 case GERBV_APTYPE_MACRO_POLYGON:
584 gerbv_gdk_draw_prim5(pixmap, gc, ls->parameter, scale, x, y);
585 dprintf(" Polygon\n");
586 break;
587 case GERBV_APTYPE_MACRO_MOIRE:
588 gerbv_gdk_draw_prim6(pixmap, gc, ls->parameter, scale, x, y);
589 dprintf(" Moiré\n");
590 break;
591 case GERBV_APTYPE_MACRO_THERMAL:
592 gerbv_gdk_draw_prim7(pixmap, gc, ls->parameter, scale, x, y);
593 dprintf(" Thermal\n");
594 break;
595 case GERBV_APTYPE_MACRO_LINE20:
596 gerbv_gdk_draw_prim20(pixmap, gc, ls->parameter, scale, x, y);
597 dprintf(" Line 20\n");
598 break;
599 case GERBV_APTYPE_MACRO_LINE21:
600 gerbv_gdk_draw_prim21(pixmap, gc, ls->parameter, scale, x, y);
601 dprintf(" Line 21\n");
602 break;
603 case GERBV_APTYPE_MACRO_LINE22:
604 gerbv_gdk_draw_prim22(pixmap, gc, ls->parameter, scale, x, y);
605 dprintf(" Line 22\n");
606 break;
607 default:
608 GERB_FATAL_ERROR("Unknown simplified aperture macro");
611 ls = ls->next;
614 } /* gerbv_gdk_draw_amacro */
618 * Draws a circle _centered_ at x,y with diameter dia
620 static void
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);
630 return;
631 } /* gerbv_gdk_draw_circle */
635 * Draws a rectangle _centered_ at x,y with sides x_side, y_side
637 static void
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);
647 return;
648 } /* gerbv_gdk_draw_rectangle */
652 * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
654 static void
655 gerbv_gdk_draw_oval(GdkPixmap *pixmap, GdkGC *gc,
656 gint filled, gint x, gint y, gint x_axis, gint y_axis)
658 gint delta = 0;
659 GdkGC *local_gc = gdk_gc_new(pixmap);
661 gdk_gc_copy(local_gc, gc);
663 if (x_axis > y_axis) {
664 /* Draw in x axis */
665 delta = x_axis / 2 - y_axis / 2;
666 gdk_gc_set_line_attributes(local_gc, y_axis,
667 GDK_LINE_SOLID,
668 GDK_CAP_ROUND,
669 GDK_JOIN_MITER);
670 gdk_draw_line(pixmap, local_gc, x - delta, y, x + delta, y);
671 } else {
672 /* Draw in y axis */
673 delta = y_axis / 2 - x_axis / 2;
674 gdk_gc_set_line_attributes(local_gc, x_axis,
675 GDK_LINE_SOLID,
676 GDK_CAP_ROUND,
677 GDK_JOIN_MITER);
678 gdk_draw_line(pixmap, local_gc, x, y - delta, x, y + delta);
681 gdk_gc_unref(local_gc);
683 return;
684 } /* gerbv_gdk_draw_oval */
688 * Draws an arc
689 * Draws an arc _centered_ at x,y
690 * direction: 0 counterclockwise, 1 clockwise
692 static void
693 gerbv_gdk_draw_arc(GdkPixmap *pixmap, GdkGC *gc,
694 int x, int y,
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)));
704 return;
705 } /* gerbv_gdk_draw_arc */
707 void
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;
716 int steps,i;
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 */
721 curr_point_idx = 0;
722 pointArraySize = 0;
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;
758 curr_point_idx++;
759 break;
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
763 with GDK */
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);
775 curr_point_idx++;
777 break;
778 case GERBV_INTERPOLATION_PAREA_END :
779 gdk_gc_copy(pgc, gc);
780 gdk_gc_set_line_attributes(pgc, 1,
781 GDK_LINE_SOLID,
782 GDK_CAP_PROJECTING,
783 GDK_JOIN_MITER);
784 gdk_draw_polygon(*pixmap, pgc, 1, points, curr_point_idx);
785 g_free(points);
786 points = NULL;
787 return;
788 default:
789 break;
792 return;
795 void
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);
801 /* apply offset */
802 cairo_matrix_translate (fullMatrix, state->offsetA, state->offsetB);
803 /* apply mirror */
804 switch (state->mirrorState) {
805 case GERBV_MIRROR_STATE_FLIPA:
806 cairo_matrix_scale (fullMatrix, -1, 1);
807 cairo_matrix_scale (scaleMatrix, -1, 1);
808 break;
809 case GERBV_MIRROR_STATE_FLIPB:
810 cairo_matrix_scale (fullMatrix, 1, -1);
811 cairo_matrix_scale (scaleMatrix, -1, 1);
812 break;
813 case GERBV_MIRROR_STATE_FLIPAB:
814 cairo_matrix_scale (fullMatrix, -1, -1);
815 cairo_matrix_scale (scaleMatrix, -1, 1);
816 break;
817 default:
818 break;
820 /* finally, apply axis select */
821 if (state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
822 /* we do this by rotating 270 (counterclockwise, then mirroring
823 the Y axis */
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,
835 gchar drawMode,
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;
845 gint x1, y1, x2, y2;
846 glong xlong1, ylong1, xlong2, ylong2;
847 int p1, p2;
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;
852 gdouble tempX,tempY;
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;
858 else
859 polarity = GERBV_POLARITY_POSITIVE;
860 } else {
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
868 // optimizations
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);
885 /* offset image */
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)
893 scaleY *= -1;
894 if (transform.mirrorAroundY)
895 scaleX *= -1;
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
918 gdk_gc_unref(gc);
919 gdk_gc_unref(pgc);
921 return 0;
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);
935 } else {
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
958 for it */
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) {
970 int i;
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)
977 foundNet = TRUE;
979 if (!foundNet)
980 continue;
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))) {
992 continue;
996 * If circle segment, scale and translate that one too
998 if (net->cirseg) {
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);
1019 else
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);
1029 continue;
1030 /* make sure we completely skip over any deleted nodes */
1031 case GERBV_INTERPOLATION_DELETED:
1032 continue;
1033 default :
1034 break;
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);
1048 continue;
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))
1069 continue;
1070 if ((ylong1 < -10000) && (ylong2 < -10000))
1071 continue;
1072 if ((xlong1 > 10000) && (xlong2 > 10000))
1073 continue;
1074 if ((ylong1 > 10000) && (ylong2 > 10000))
1075 continue;
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,
1102 GDK_LINE_SOLID,
1103 GDK_CAP_PROJECTING,
1104 GDK_JOIN_MITER);
1105 else
1106 gdk_gc_set_line_attributes(gc, p1,
1107 GDK_LINE_SOLID,
1108 GDK_CAP_ROUND,
1109 GDK_JOIN_MITER);
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,
1118 GDK_CAP_ROUND,
1119 GDK_JOIN_MITER);
1120 gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
1121 gdk_gc_set_line_attributes(gc, p1,
1122 GDK_LINE_SOLID,
1123 GDK_CAP_ROUND,
1124 GDK_JOIN_MITER);
1125 break;
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);
1129 else {
1130 gint dx, dy;
1131 GdkPoint poly[6];
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);
1149 break;
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);
1154 break;
1155 default :
1156 break;
1158 break;
1159 case GERBV_APERTURE_STATE_OFF :
1160 break;
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.
1179 if (p2) {
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);
1185 } else {
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);
1192 break;
1193 case GERBV_APTYPE_RECTANGLE:
1194 gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
1195 break;
1196 case GERBV_APTYPE_OVAL :
1197 gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
1198 break;
1199 case GERBV_APTYPE_POLYGON :
1200 gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
1201 break;
1202 case GERBV_APTYPE_MACRO :
1203 gerbv_gdk_draw_amacro(*pixmap, gc,
1204 image->aperture[net->aperture]->simplified,
1205 scale, x2, y2);
1206 break;
1207 default :
1208 GERB_MESSAGE("Unknown aperture type\n");
1209 return 0;
1211 break;
1212 default :
1213 GERB_MESSAGE("Unknown aperture state\n");
1214 return 0;
1220 * Destroy GCs before exiting
1222 gdk_gc_unref(gc);
1223 gdk_gc_unref(pgc);
1225 return 1;
1227 } /* image2pixmap */