gerbv  2.6A
draw-gdk.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This file is a part of gerbv.
4  *
5  * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
6  *
7  * $Id$
8  *
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.
13  *
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.
18  *
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
22  */
23 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h> /* ceil(), atan2() */
36 
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 
41 #include <gtk/gtk.h>
42 #include "gerbv.h"
43 #include "draw-gdk.h"
44 #include "common.h"
45 
46 #undef round
47 #define round(x) ceil((double)(x))
48 
49 #define dprintf if(DEBUG) printf
50 
51 /*
52  * If you want to rotate a
53  * column vector v by t degrees using matrix M, use
54  *
55  * M = {{cos t, -sin t}, {sin t, cos t}} in M*v.
56  *
57  * From comp.graphics.algorithms Frequently Asked Questions
58  *
59  * Due reverse defintion of X-axis in GTK you have to negate
60  * angels.
61  *
62  */
63 static GdkPoint
64 rotate_point(GdkPoint point, int angle)
65 {
66  double sint, cost;
67  GdkPoint returned;
68 
69  if (angle == 0)
70  return point;
71 
72  sint = sin(-(double)angle * M_PI / 180.0);
73  cost = cos(-(double)angle * M_PI / 180.0);
74 
75  returned.x = (int)round(cost * (double)point.x - sint * (double)point.y);
76  returned.y = (int)round(sint * (double)point.x + cost * (double)point.y);
77 
78  return returned;
79 }
80 
81 
82 /*
83  * Aperture macro primitive 1 (Circle)
84  */
85 static void
86 gerbv_gdk_draw_prim1(GdkPixmap *pixmap, GdkGC *gc, double *p,
87  double scale, gint x, gint y)
88 {
89  const int exposure_idx = 0;
90  const int diameter_idx = 1;
91  const int x_offset_idx = 2;
92  const int y_offset_idx = 3;
93  const gint full_circle = 23360;
94  GdkGC *local_gc = gdk_gc_new(pixmap);
95  gint dia = round(fabs(p[diameter_idx] * scale));
96  gint real_x = x - dia / 2;
97  gint real_y = y - dia / 2;
98  GdkColor color;
99 
100  gdk_gc_copy(local_gc, gc);
101 
102  real_x += (int)(p[x_offset_idx] * (double)scale);
103  real_y -= (int)(p[y_offset_idx] * (double)scale);
104 
105  /* Exposure */
106  if (p[exposure_idx] == 0.0) {
107  color.pixel = 0;
108  gdk_gc_set_foreground(local_gc, &color);
109  }
110 
111  gdk_gc_set_line_attributes(local_gc,
112  1, /* outline always 1 pixels */
113  GDK_LINE_SOLID,
114  GDK_CAP_BUTT,
115  GDK_JOIN_MITER);
116 
117  /*
118  * A filled circle
119  */
120  gdk_draw_arc(pixmap, local_gc, 1, real_x, real_y, dia, dia,
121  0, full_circle);
122 
123  gdk_gc_unref(local_gc);
124 
125  return;
126 } /* gerbv_gdk_draw_prim1 */
127 
128 
129 /*
130  * Aperture macro primitive 4 (outline)
131  * - Start point is not included in number of points.
132  * - Outline is 1 pixel.
133  */
134 static void
135 gerbv_gdk_draw_prim4(GdkPixmap *pixmap, GdkGC *gc, double *p,
136  double scale, gint x, gint y)
137 {
138  const int exposure_idx = 0;
139  const int nuf_points_idx = 1;
140  const int first_x_idx = 2;
141  const int first_y_idx = 3;
142  const int rotext_idx = 4;
143  GdkGC *local_gc = gdk_gc_new(pixmap);
144  int nuf_points, point;
145  double rotation;
146  GdkPoint *points;
147  GdkColor color;
148 
149  /* Include start point */
150  nuf_points = (int)p[nuf_points_idx] + 1;
151  points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_points);
152  if (!points) {
153  g_free(points);
154  return;
155  }
156 
157  rotation = p[(nuf_points - 1) * 2 + rotext_idx];
158  for (point = 0; point < nuf_points; point++) {
159  points[point].x = (int)round(scale * p[point * 2 + first_x_idx]);
160  points[point].y = -(int)round(scale * p[point * 2 + first_y_idx]);
161  if (rotation != 0.0)
162  points[point] = rotate_point(points[point], rotation);
163  points[point].x += x;
164  points[point].y += y;
165  }
166 
167  gdk_gc_copy(local_gc, gc);
168 
169  /* Exposure */
170  if (p[exposure_idx] == 0.0) {
171  color.pixel = 0;
172  gdk_gc_set_foreground(local_gc, &color);
173  }
174 
175  gdk_gc_set_line_attributes(local_gc,
176  1, /* outline always 1 pixels */
177  GDK_LINE_SOLID,
178  GDK_CAP_BUTT,
179  GDK_JOIN_MITER);
180  gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
181 
182  g_free(points);
183 
184  gdk_gc_unref(local_gc);
185 
186  return;
187 } /* gerbv_gdk_draw_prim4 */
188 
189 
190 /*
191  * Aperture macro primitive 5 (polygon)
192  */
193 static void
194 gerbv_gdk_draw_prim5(GdkPixmap *pixmap, GdkGC *gc, double *p,
195  double scale, gint x, gint y)
196 {
197  const int exposure_idx = 0;
198  const int nuf_vertices_idx = 1;
199  const int center_x_idx = 2;
200  const int center_y_idx = 3;
201  const int diameter_idx = 4;
202  const int rotation_idx = 5;
203  int nuf_vertices, i;
204  double vertex, tick, rotation, radius;
205  GdkPoint *points;
206  GdkGC *local_gc = gdk_gc_new(pixmap);
207  GdkColor color;
208 
209  nuf_vertices = (int)p[nuf_vertices_idx];
210  points = (GdkPoint *)g_malloc(sizeof(GdkPoint) * nuf_vertices);
211  if (!points) {
212  g_free(points);
213  return;
214  }
215 
216  gdk_gc_copy(local_gc, gc);
217 
218  /* Exposure */
219  if (p[exposure_idx] == 0.0) {
220  color.pixel = 0;
221  gdk_gc_set_foreground(local_gc, &color);
222  }
223 
224  tick = 2 * M_PI / (double)nuf_vertices;
225  rotation = -p[rotation_idx] * M_PI / 180.0;
226  radius = p[diameter_idx] / 2.0;
227  for (i = 0; i < nuf_vertices; i++) {
228  vertex = tick * (double)i + rotation;
229  points[i].x = (int)round(scale * radius * cos(vertex)) + x +
230  p[center_x_idx];
231  points[i].y = (int)round(scale * radius * sin(vertex)) + y +
232  p[center_y_idx];
233  }
234 
235  gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_vertices);
236 
237  gdk_gc_unref(local_gc);
238 
239  g_free(points);
240  return;
241 } /* gerbv_gdk_draw_prim5 */
242 
243 
244 /*
245  * Doesn't handle and explicit x,y yet
246  * Questions:
247  * - is "gap" distance between edges of circles or distance between
248  * center of line of circle?
249  */
250 static void
251 gerbv_gdk_draw_prim6(GdkPixmap *pixmap, GdkGC *gc, double *p,
252  double scale, gint x, gint y)
253 {
254  const int outside_dia_idx = 2;
255  const int ci_thickness_idx = 3;
256  const int gap_idx = 4;
257  const int nuf_circles_idx = 5;
258  const int ch_thickness_idx = 6;
259  const int ch_length_idx = 7;
260  const int rotation_idx = 8;
261  GdkGC *local_gc = gdk_gc_new(pixmap);
262  double real_dia;
263  double real_dia_diff;
264  int circle;
265  GdkPoint crosshair[4];
266  int point;
267 
268  gdk_gc_copy(local_gc, gc);
269  gdk_gc_set_line_attributes(local_gc,
270  (int)round(scale * p[ci_thickness_idx]),
271  GDK_LINE_SOLID,
272  GDK_CAP_BUTT,
273  GDK_JOIN_MITER);
274 
275  real_dia = p[outside_dia_idx] - p[ci_thickness_idx] / 2.0;
276  real_dia_diff = 2*(p[gap_idx] + p[ci_thickness_idx]);
277 
278  for (circle = 0; circle != (int)p[nuf_circles_idx]; circle++) {
279  /*
280  * Non filled circle
281  */
282  const gint full_circle = 23360;
283  gint dia = (real_dia - real_dia_diff * circle) * scale;
284  if (dia >= 0){
285  gdk_draw_arc(pixmap, local_gc, 0, x - dia / 2, y - dia / 2,
286  dia, dia, 0, full_circle);
287  }
288  }
289 
290  /*
291  * Cross Hair
292  */
293  memset(crosshair, 0, sizeof(GdkPoint) * 4);
294  crosshair[0].x = (int)((p[ch_length_idx] / 2.0) * scale);
295  /*crosshair[0].y = 0;*/
296  crosshair[1].x = -crosshair[0].x;
297  /*crosshair[1].y = 0;*/
298  /*crosshair[2].x = 0;*/
299  crosshair[2].y = crosshair[0].x;
300  /*crosshair[3].x = 0;*/
301  crosshair[3].y = -crosshair[0].x;
302 
303  gdk_gc_set_line_attributes(local_gc,
304  (int)round(scale * p[ch_thickness_idx]),
305  GDK_LINE_SOLID,
306  GDK_CAP_BUTT,
307  GDK_JOIN_MITER);
308 
309  for (point = 0; point < 4; point++) {
310  crosshair[point] = rotate_point(crosshair[point],
311  p[rotation_idx]);
312  crosshair[point].x += x;
313  crosshair[point].y += y;
314  }
315  gdk_draw_line(pixmap, local_gc,
316  crosshair[0].x, crosshair[0].y,
317  crosshair[1].x, crosshair[1].y);
318  gdk_draw_line(pixmap, local_gc,
319  crosshair[2].x, crosshair[2].y,
320  crosshair[3].x, crosshair[3].y);
321 
322  gdk_gc_unref(local_gc);
323 
324  return;
325 } /* gerbv_gdk_draw_prim6 */
326 
327 
328 static void
329 gerbv_gdk_draw_prim7(GdkPixmap *pixmap, GdkGC *gc, double *p,
330  double scale, gint x, gint y)
331 {
332  const int outside_dia_idx = 2;
333  const int inside_dia_idx = 3;
334  const int ch_thickness_idx = 4;
335  const int rotation_idx = 5;
336  const gint full_circle = 23360;
337  GdkGCValues gc_val;
338  int diameter, i;
339  GdkGC *local_gc = gdk_gc_new(pixmap);
340  GdkPoint point[4];
341  double ci_thickness = (p[outside_dia_idx] -
342  p[inside_dia_idx]) / 2.0;
343 
344  gdk_gc_copy(local_gc, gc);
345  gdk_gc_set_line_attributes(local_gc,
346  (int)round(scale * ci_thickness),
347  GDK_LINE_SOLID,
348  GDK_CAP_BUTT,
349  GDK_JOIN_MITER);
350 
351  /*
352  * Non filled circle
353  */
354  diameter = (p[inside_dia_idx] + ci_thickness) * scale;
355  gdk_draw_arc(pixmap, local_gc, 0, x - diameter / 2, y - diameter / 2,
356  diameter, diameter, 0, full_circle);
357 
358  /*
359  * Cross hair
360  */
361  /* Calculate the end points of the crosshair */
362  /* GDK doesn't always remove all of the circle (round of error probably)
363  I extend the crosshair line with 2 (one pixel in each end) to make
364  sure all of the circle is removed with the crosshair */
365  for (i = 0; i < 4; i++) {
366  point[i].x = round((p[outside_dia_idx] / 2.0) * scale) + 2;
367  point[i].y = 0;
368  point[i] = rotate_point(point[i], p[rotation_idx] + 90 * i);
369  point[i].x += x;
370  point[i].y += y;
371  }
372 
373  gdk_gc_set_line_attributes(local_gc,
374  (int)round(scale * p[ch_thickness_idx]),
375  GDK_LINE_SOLID,
376  GDK_CAP_BUTT,
377  GDK_JOIN_MITER);
378 
379  /* The cross hair should "cut out" parts of the circle, hence inverse */
380  gdk_gc_get_values(local_gc, &gc_val);
381  if (gc_val.foreground.pixel == 1)
382  gc_val.foreground.pixel = 0;
383  else
384  gc_val.foreground.pixel = 1;
385  gdk_gc_set_foreground(local_gc, &(gc_val.foreground));
386 
387  /* Draw the actual cross */
388  gdk_draw_line(pixmap, local_gc,
389  point[0].x, point[0].y, point[2].x, point[2].y);
390  gdk_draw_line(pixmap, local_gc,
391  point[1].x, point[1].y, point[3].x, point[3].y);
392 
393  gdk_gc_unref(local_gc);
394 
395  return;
396 } /* gerbv_gdk_draw_prim7 */
397 
398 
399 /*
400  * Doesn't handle and explicit x,y yet
401  */
402 static void
403 gerbv_gdk_draw_prim20(GdkPixmap *pixmap, GdkGC *gc, double *p,
404  double scale, gint x, gint y)
405 {
406  const int exposure_idx = 0;
407  const int linewidth_idx = 1;
408  const int start_x_idx = 2;
409  const int start_y_idx = 3;
410  const int end_x_idx = 4;
411  const int end_y_idx = 5;
412  const int rotation_idx = 6;
413  const int nuf_points = 2;
414  GdkGC *local_gc = gdk_gc_new(pixmap);
415  GdkPoint points[nuf_points];
416  GdkColor color;
417  int i;
418 
419  gdk_gc_copy(local_gc, gc);
420 
421  /* Exposure */
422  if (p[exposure_idx] == 0.0) {
423  color.pixel = 0;
424  gdk_gc_set_foreground(local_gc, &color);
425  }
426 
427  gdk_gc_set_line_attributes(local_gc,
428  (int)round(scale * p[linewidth_idx]),
429  GDK_LINE_SOLID,
430  GDK_CAP_BUTT,
431  GDK_JOIN_MITER);
432 
433  points[0].x = (p[start_x_idx] * scale);
434  points[0].y = (p[start_y_idx] * scale);
435  points[1].x = (p[end_x_idx] * scale);
436  points[1].y = (p[end_y_idx] * scale);
437 
438  for (i = 0; i < nuf_points; i++) {
439  points[i] = rotate_point(points[i], -p[rotation_idx]);
440  points[i].x = x + points[i].x;
441  points[i].y = y - points[i].y;
442  }
443 
444  gdk_draw_line(pixmap, local_gc,
445  points[0].x, points[0].y,
446  points[1].x, points[1].y);
447 
448  gdk_gc_unref(local_gc);
449 
450  return;
451 } /* gerbv_gdk_draw_prim20 */
452 
453 
454 static void
455 gerbv_gdk_draw_prim21(GdkPixmap *pixmap, GdkGC *gc, double *p,
456  double scale, gint x, gint y)
457 {
458  const int exposure_idx = 0;
459  const int width_idx = 1;
460  const int height_idx = 2;
461  const int exp_x_idx = 3;
462  const int exp_y_idx = 4;
463  const int rotation_idx = 5;
464  const int nuf_points = 4;
465  GdkPoint points[nuf_points];
466  GdkColor color;
467  GdkGC *local_gc = gdk_gc_new(pixmap);
468  int half_width, half_height;
469  int i;
470 
471  half_width = (int)round(p[width_idx] * scale / 2.0);
472  half_height =(int)round(p[height_idx] * scale / 2.0);
473 
474  points[0].x = half_width;
475  points[0].y = half_height;
476 
477  points[1].x = half_width;
478  points[1].y = -half_height;
479 
480  points[2].x = -half_width;
481  points[2].y = -half_height;
482 
483  points[3].x = -half_width;
484  points[3].y = half_height;
485 
486  for (i = 0; i < nuf_points; i++) {
487  points[i] = rotate_point(points[i], p[rotation_idx]);
488  points[i].x += (x + (int)(p[exp_x_idx] * scale));
489  points[i].y += (y - (int)(p[exp_y_idx] * scale));
490  }
491 
492  gdk_gc_copy(local_gc, gc);
493 
494  /* Exposure */
495  if (p[exposure_idx] == 0.0) {
496  color.pixel = 0;
497  gdk_gc_set_foreground(local_gc, &color);
498  }
499 
500  gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
501 
502  gdk_gc_unref(local_gc);
503 
504  return;
505 } /* gerbv_gdk_draw_prim21 */
506 
507 
508 /*
509  * Doesn't handle explicit x,y yet
510  */
511 static void
512 gerbv_gdk_draw_prim22(GdkPixmap *pixmap, GdkGC *gc, double *p,
513  double scale, gint x, gint y)
514 {
515  const int exposure_idx = 0;
516  const int width_idx = 1;
517  const int height_idx = 2;
518  const int x_lower_left_idx = 3;
519  const int y_lower_left_idx = 4;
520  const int rotation_idx = 5;
521  const int nuf_points = 4;
522  GdkPoint points[nuf_points];
523  GdkGC *local_gc = gdk_gc_new(pixmap);
524  GdkColor color;
525  int i;
526 
527  points[0].x = (int)round(p[x_lower_left_idx] * scale);
528  points[0].y = (int)round(p[y_lower_left_idx] * scale);
529 
530  points[1].x = (int)round((p[x_lower_left_idx] + p[width_idx])
531  * scale);
532  points[1].y = (int)round(p[y_lower_left_idx] * scale);
533 
534  points[2].x = (int)round((p[x_lower_left_idx] + p[width_idx])
535  * scale);
536  points[2].y = (int)round((p[y_lower_left_idx] + p[height_idx])
537  * scale);
538 
539  points[3].x = (int)round(p[x_lower_left_idx] * scale);
540  points[3].y = (int)round((p[y_lower_left_idx] + p[height_idx])
541  * scale);
542 
543  for (i = 0; i < nuf_points; i++) {
544  points[i] = rotate_point(points[i], p[rotation_idx]);
545  points[i].x = x + points[i].x;
546  points[i].y = y - points[i].y;
547  }
548 
549  gdk_gc_copy(local_gc, gc);
550 
551  /* Exposure */
552  if (p[exposure_idx] == 0.0) {
553  color.pixel = 0;
554  gdk_gc_set_foreground(local_gc, &color);
555  }
556 
557  gdk_draw_polygon(pixmap, local_gc, 1, points, nuf_points);
558 
559  gdk_gc_unref(local_gc);
560 
561  return;
562 } /* gerbv_gdk_draw_prim22 */
563 
564 
565 static void
566 gerbv_gdk_draw_amacro(GdkPixmap *pixmap, GdkGC *gc,
567  gerbv_simplified_amacro_t *s, double scale,
568  gint x, gint y)
569 {
570  gerbv_simplified_amacro_t *ls = s;
571 
572  dprintf(_("Drawing simplified aperture macros:\n"));
573  while (ls != NULL) {
574 
575  switch (ls->type) {
577  gerbv_gdk_draw_prim1(pixmap, gc, ls->parameter, scale, x, y);
578  dprintf(_(" Circle\n"));
579  break;
581  gerbv_gdk_draw_prim4(pixmap, gc, ls->parameter, scale, x, y);
582  dprintf(_(" Outline\n"));
583  break;
585  gerbv_gdk_draw_prim5(pixmap, gc, ls->parameter, scale, x, y);
586  dprintf(_(" Polygon\n"));
587  break;
589  gerbv_gdk_draw_prim6(pixmap, gc, ls->parameter, scale, x, y);
590  dprintf(_(" Moire\n"));
591  break;
593  gerbv_gdk_draw_prim7(pixmap, gc, ls->parameter, scale, x, y);
594  dprintf(_(" Thermal\n"));
595  break;
597  gerbv_gdk_draw_prim20(pixmap, gc, ls->parameter, scale, x, y);
598  dprintf(_(" Line 20\n"));
599  break;
601  gerbv_gdk_draw_prim21(pixmap, gc, ls->parameter, scale, x, y);
602  dprintf(_(" Line 21\n"));
603  break;
605  gerbv_gdk_draw_prim22(pixmap, gc, ls->parameter, scale, x, y);
606  dprintf(_(" Line 22\n"));
607  break;
608  default:
609  GERB_FATAL_ERROR(_("Unknown simplified aperture macro"));
610  }
611 
612  ls = ls->next;
613  }
614 
615 } /* gerbv_gdk_draw_amacro */
616 
617 
618 /*
619  * Draws a circle _centered_ at x,y with diameter dia
620  */
621 static void
622 gerbv_gdk_draw_circle(GdkPixmap *pixmap, GdkGC *gc,
623  gint filled, gint x, gint y, gint dia)
624 {
625  static const gint full_circle = 23360;
626  gint real_x = x - dia / 2;
627  gint real_y = y - dia / 2;
628 
629  gdk_draw_arc(pixmap, gc, filled, real_x, real_y, dia, dia, 0, full_circle);
630 
631  return;
632 } /* gerbv_gdk_draw_circle */
633 
634 
635 /*
636  * Draws a rectangle _centered_ at x,y with sides x_side, y_side
637  */
638 static void
639 gerbv_gdk_draw_rectangle(GdkPixmap *pixmap, GdkGC *gc,
640  gint filled, gint x, gint y, gint x_side, gint y_side)
641 {
642 
643  gint real_x = x - x_side / 2;
644  gint real_y = y - y_side / 2;
645 
646  gdk_draw_rectangle(pixmap, gc, filled, real_x, real_y, x_side, y_side);
647 
648  return;
649 } /* gerbv_gdk_draw_rectangle */
650 
651 
652 /*
653  * Draws an oval _centered_ at x,y with x axis x_axis and y axis y_axis
654  */
655 static void
656 gerbv_gdk_draw_oval(GdkPixmap *pixmap, GdkGC *gc,
657  gint filled, gint x, gint y, gint x_axis, gint y_axis)
658 {
659  gint delta = 0;
660  GdkGC *local_gc = gdk_gc_new(pixmap);
661 
662  gdk_gc_copy(local_gc, gc);
663 
664  if (x_axis > y_axis) {
665  /* Draw in x axis */
666  delta = x_axis / 2 - y_axis / 2;
667  gdk_gc_set_line_attributes(local_gc, y_axis,
668  GDK_LINE_SOLID,
669  GDK_CAP_ROUND,
670  GDK_JOIN_MITER);
671  gdk_draw_line(pixmap, local_gc, x - delta, y, x + delta, y);
672  } else {
673  /* Draw in y axis */
674  delta = y_axis / 2 - x_axis / 2;
675  gdk_gc_set_line_attributes(local_gc, x_axis,
676  GDK_LINE_SOLID,
677  GDK_CAP_ROUND,
678  GDK_JOIN_MITER);
679  gdk_draw_line(pixmap, local_gc, x, y - delta, x, y + delta);
680  }
681 
682  gdk_gc_unref(local_gc);
683 
684  return;
685 } /* gerbv_gdk_draw_oval */
686 
687 
688 /*
689  * Draws an arc
690  * Draws an arc _centered_ at x,y
691  * direction: 0 counterclockwise, 1 clockwise
692  */
693 static void
694 gerbv_gdk_draw_arc(GdkPixmap *pixmap, GdkGC *gc,
695  int x, int y,
696  int width, int height,
697  double angle1, double angle2)
698 {
699  gint real_x = x - width / 2;
700  gint real_y = y - height / 2;
701 
702  gdk_draw_arc(pixmap, gc, FALSE, real_x, real_y, width, height,
703  (gint)(angle1 * 64.0), (gint)(((angle2 - angle1) * 64.0)));
704 
705  return;
706 } /* gerbv_gdk_draw_arc */
707 
708 void
709 draw_gdk_render_polygon_object (gerbv_net_t *oldNet, gerbv_image_t *image, double sr_x, double sr_y,
710  cairo_matrix_t *fullMatrix, cairo_matrix_t *scaleMatrix, GdkGC *gc, GdkGC *pgc,
711  GdkPixmap **pixmap) {
712  gerbv_net_t *currentNet;
713  gint x2,y2,cp_x=0,cp_y=0,cir_width=0;
714  GdkPoint *points = NULL;
715  int pointArraySize=0;
716  int curr_point_idx = 0;
717  int steps,i;
718  gdouble angleDiff, tempX, tempY;
719 
720  /* save the first net in the polygon as the "ID" net pointer
721  in case we are saving this net to the selection array */
722  curr_point_idx = 0;
723  pointArraySize = 0;
724 
725  for (currentNet = oldNet->next; currentNet!=NULL; currentNet = currentNet->next){
726  tempX = currentNet->stop_x + sr_x;
727  tempY = currentNet->stop_y + sr_y;
728  cairo_matrix_transform_point (fullMatrix, &tempX, &tempY);
729  x2 = (int)round(tempX);
730  y2 = (int)round(tempY);
731 
732  /*
733  * If circle segment, scale and translate that one too
734  */
735  if (currentNet->cirseg) {
736  tempX = currentNet->cirseg->width;
737  tempY = currentNet->cirseg->height;
738  cairo_matrix_transform_point (scaleMatrix, &tempX, &tempY);
739  cir_width = (int)round(tempX);
740 
741  tempX = currentNet->cirseg->cp_x + sr_x;
742  tempY = currentNet->cirseg->cp_y + sr_y;
743  cairo_matrix_transform_point (fullMatrix, &tempX, &tempY);
744  cp_x = (int)round(tempX);
745  cp_y = (int)round(tempY);
746  }
747 
748  switch (currentNet->interpolation) {
753  if (pointArraySize < (curr_point_idx + 1)) {
754  points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) * (curr_point_idx + 1));
755  pointArraySize = (curr_point_idx + 1);
756  }
757  points[curr_point_idx].x = x2;
758  points[curr_point_idx].y = y2;
759  curr_point_idx++;
760  break;
763  /* we need to chop up the arc into small lines for rendering
764  with GDK */
765  angleDiff = currentNet->cirseg->angle2 - currentNet->cirseg->angle1;
766  steps = (int) abs(angleDiff);
767  if (pointArraySize < (curr_point_idx + steps)) {
768  points = (GdkPoint *)g_realloc(points,sizeof(GdkPoint) * (curr_point_idx + steps));
769  pointArraySize = (curr_point_idx + steps);
770  }
771  for (i=0; i<steps; i++){
772  points[curr_point_idx].x = cp_x + cir_width / 2.0 * cos ((currentNet->cirseg->angle1 +
773  (angleDiff * i) / steps)*M_PI/180);
774  points[curr_point_idx].y = cp_y - cir_width / 2.0 * sin ((currentNet->cirseg->angle1 +
775  (angleDiff * i) / steps)*M_PI/180);
776  curr_point_idx++;
777  }
778  break;
780  gdk_gc_copy(pgc, gc);
781  gdk_gc_set_line_attributes(pgc, 1,
782  GDK_LINE_SOLID,
783  GDK_CAP_PROJECTING,
784  GDK_JOIN_MITER);
785  gdk_draw_polygon(*pixmap, pgc, 1, points, curr_point_idx);
786  g_free(points);
787  points = NULL;
788  return;
789  default:
790  break;
791  }
792  }
793  return;
794 }
795 
796 void
797 draw_gdk_apply_netstate_transformation (cairo_matrix_t *fullMatrix, cairo_matrix_t *scaleMatrix,
798  gerbv_netstate_t *state) {
799  /* apply scale factor */
800  cairo_matrix_scale (fullMatrix, state->scaleA, state->scaleB);
801  cairo_matrix_scale (scaleMatrix, state->scaleA, state->scaleB);
802  /* apply offset */
803  cairo_matrix_translate (fullMatrix, state->offsetA, state->offsetB);
804  /* apply mirror */
805  switch (state->mirrorState) {
806  case GERBV_MIRROR_STATE_FLIPA:
807  cairo_matrix_scale (fullMatrix, -1, 1);
808  cairo_matrix_scale (scaleMatrix, -1, 1);
809  break;
810  case GERBV_MIRROR_STATE_FLIPB:
811  cairo_matrix_scale (fullMatrix, 1, -1);
812  cairo_matrix_scale (scaleMatrix, -1, 1);
813  break;
814  case GERBV_MIRROR_STATE_FLIPAB:
815  cairo_matrix_scale (fullMatrix, -1, -1);
816  cairo_matrix_scale (scaleMatrix, -1, 1);
817  break;
818  default:
819  break;
820  }
821  /* finally, apply axis select */
822  if (state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
823  /* we do this by rotating 270 (counterclockwise, then mirroring
824  the Y axis */
825  cairo_matrix_rotate (fullMatrix, 3 * M_PI / 2);
826  cairo_matrix_scale (fullMatrix, 1, -1);
827  }
828 }
829 
830 /*
831  * Convert a gerber image to a GDK clip mask to be used when creating pixmap
832  */
833 int
834 draw_gdk_image_to_pixmap(GdkPixmap **pixmap, gerbv_image_t *image,
835  double scale, double trans_x, double trans_y,
836  gchar drawMode,
837  gerbv_selection_info_t *selectionInfo, gerbv_render_info_t *renderInfo,
838  gerbv_user_transformation_t transform)
839 {
840  GdkGC *gc = gdk_gc_new(*pixmap);
841  GdkGC *pgc = gdk_gc_new(*pixmap);
842  GdkGCValues gc_values;
843  struct gerbv_net *net;
844  gerbv_netstate_t *oldState;
845  gerbv_layer_t *oldLayer;
846  gint x1, y1, x2, y2;
847  glong xlong1, ylong1, xlong2, ylong2;
848  int p1, p2;
849  int cir_width = 0, cir_height = 0;
850  int cp_x = 0, cp_y = 0;
851  GdkColor transparent, opaque;
852  gerbv_polarity_t polarity;
853  gdouble tempX,tempY;
854  gdouble minX=0,minY=0,maxX=0,maxY=0;
855 
856  if (transform.inverted) {
857  if (image->info->polarity == GERBV_POLARITY_POSITIVE)
858  polarity = GERBV_POLARITY_NEGATIVE;
859  else
860  polarity = GERBV_POLARITY_POSITIVE;
861  } else {
862  polarity = image->info->polarity;
863  }
864  if (drawMode == DRAW_SELECTIONS)
865  polarity = GERBV_POLARITY_POSITIVE;
866 
867  gboolean useOptimizations = TRUE;
868  // if the user is using any transformations for this layer, then don't bother using rendering
869  // optimizations
870  if ((fabs(transform.translateX) > 0.00001) ||
871  (fabs(transform.translateY) > 0.00001) ||
872  (fabs(transform.scaleX - 1) > 0.00001) ||
873  (fabs(transform.scaleY - 1) > 0.00001) ||
874  (fabs(transform.rotation) > 0.00001) ||
875  transform.mirrorAroundX || transform.mirrorAroundY)
876  useOptimizations = FALSE;
877 
878  // calculate the transformation matrix for the user_transformation options
879  cairo_matrix_t fullMatrix, scaleMatrix;
880  cairo_matrix_init (&fullMatrix, 1, 0, 0, 1, 0, 0);
881  cairo_matrix_init (&scaleMatrix, 1, 0, 0, 1, 0, 0);
882 
883  cairo_matrix_translate (&fullMatrix, trans_x, trans_y);
884  cairo_matrix_scale (&fullMatrix, scale, scale);
885  cairo_matrix_scale (&scaleMatrix, scale, scale);
886  /* offset image */
887 
888  cairo_matrix_translate (&fullMatrix, transform.translateX, -1*transform.translateY);
889  // don't use mirroring for the scale matrix
890  gdouble scaleX = transform.scaleX;
891  gdouble scaleY = -1*transform.scaleY;
892  cairo_matrix_scale (&scaleMatrix, scaleX, -1*scaleY);
893  if (transform.mirrorAroundX)
894  scaleY *= -1;
895  if (transform.mirrorAroundY)
896  scaleX *= -1;
897 
898  cairo_matrix_scale (&fullMatrix, scaleX, scaleY);
899  /* do image rotation */
900  cairo_matrix_rotate (&fullMatrix, transform.rotation);
901  //cairo_matrix_rotate (&scaleMatrix, transform.rotation);
902 
903  /* do image rotation */
904  cairo_matrix_rotate (&fullMatrix, image->info->imageRotation);
905 
906  if (useOptimizations) {
907  minX = renderInfo->lowerLeftX;
908  minY = renderInfo->lowerLeftY;
909  maxX = renderInfo->lowerLeftX + (renderInfo->displayWidth /
910  renderInfo->scaleFactorX);
911  maxY = renderInfo->lowerLeftY + (renderInfo->displayHeight /
912  renderInfo->scaleFactorY);
913  }
914 
915  if (image == NULL || image->netlist == NULL) {
916  /*
917  * Destroy GCs before exiting
918  */
919  gdk_gc_unref(gc);
920  gdk_gc_unref(pgc);
921 
922  return 0;
923  }
924 
925  /* Set up the two "colors" we have */
926  opaque.pixel = 0; /* opaque will not let color through */
927  transparent.pixel = 1; /* transparent will let color through */
928 
929  /*
930  * Clear clipmask and set draw color depending image on image polarity
931  */
932  if (polarity == GERBV_POLARITY_NEGATIVE) {
933  gdk_gc_set_foreground(gc, &transparent);
934  gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
935  gdk_gc_set_foreground(gc, &opaque);
936  } else {
937  gdk_gc_set_foreground(gc, &opaque);
938  gdk_draw_rectangle(*pixmap, gc, TRUE, 0, 0, -1, -1);
939  gdk_gc_set_foreground(gc, &transparent);
940  }
941  oldLayer = image->layers;
942  oldState = image->states;
943  for (net = image->netlist->next ; net != NULL; net = gerbv_image_return_next_renderable_object(net)) {
944  int repeat_X=1, repeat_Y=1;
945  double repeat_dist_X=0.0, repeat_dist_Y=0.0;
946  int repeat_i, repeat_j;
947 
948  /*
949  * If step_and_repeat (%SR%) used, repeat the drawing;
950  */
951  repeat_X = net->layer->stepAndRepeat.X;
952  repeat_Y = net->layer->stepAndRepeat.Y;
953  repeat_dist_X = net->layer->stepAndRepeat.dist_X;
954  repeat_dist_Y = net->layer->stepAndRepeat.dist_Y;
955 
956  /* check if this is a new netstate */
957  if (net->state != oldState){
958  /* it's a new state, so recalculate the new transformation matrix
959  for it */
960  draw_gdk_apply_netstate_transformation (&fullMatrix, &scaleMatrix, net->state);
961  oldState = net->state;
962  }
963  /* check if this is a new layer */
964  /* for now, only do layer rotations in GDK rendering */
965  if (net->layer != oldLayer){
966  cairo_matrix_rotate (&fullMatrix, net->layer->rotation);
967  oldLayer = net->layer;
968  }
969 
970  if (drawMode == DRAW_SELECTIONS) {
971  int i;
972  gboolean foundNet = FALSE;
973 
974  for (i=0; i<selectionInfo->selectedNodeArray->len; i++){
975  gerbv_selection_item_t sItem = g_array_index (selectionInfo->selectedNodeArray,
976  gerbv_selection_item_t, i);
977  if (sItem.net == net)
978  foundNet = TRUE;
979  }
980  if (!foundNet)
981  continue;
982  }
983 
984  for(repeat_i = 0; repeat_i < repeat_X; repeat_i++) {
985  for(repeat_j = 0; repeat_j < repeat_Y; repeat_j++) {
986  double sr_x = repeat_i * repeat_dist_X;
987  double sr_y = repeat_j * repeat_dist_Y;
988 
989  if ((useOptimizations)&&((net->boundingBox.right+sr_x < minX)
990  || (net->boundingBox.left+sr_x > maxX)
991  || (net->boundingBox.top+sr_y < minY)
992  || (net->boundingBox.bottom+sr_y > maxY))) {
993  continue;
994  }
995 
996  /*
997  * If circle segment, scale and translate that one too
998  */
999  if (net->cirseg) {
1000  tempX = net->cirseg->width;
1001  tempY = net->cirseg->height;
1002  cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
1003  cir_width = (int)round(tempX);
1004  cir_height = (int)round(tempY);
1005 
1006  tempX = net->cirseg->cp_x;
1007  tempY = net->cirseg->cp_y;
1008  cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
1009  cp_x = (int)round(tempX);
1010  cp_y = (int)round(tempY);
1011  }
1012 
1013  /*
1014  * Set GdkFunction depending on if this (gerber) layer is inverted
1015  * and allow for the photoplot being negative.
1016  */
1017  gdk_gc_set_function(gc, GDK_COPY);
1018  if ((net->layer->polarity == GERBV_POLARITY_CLEAR) != (polarity == GERBV_POLARITY_NEGATIVE))
1019  gdk_gc_set_foreground(gc, &opaque);
1020  else
1021  gdk_gc_set_foreground(gc, &transparent);
1022 
1023  /*
1024  * Polygon Area Fill routines
1025  */
1026  switch (net->interpolation) {
1028  draw_gdk_render_polygon_object (net,image,sr_x,sr_y,&fullMatrix,
1029  &scaleMatrix,gc,pgc,pixmap);
1030  continue;
1031  /* make sure we completely skip over any deleted nodes */
1033  continue;
1034  default :
1035  break;
1036  }
1037 
1038 
1039  /*
1040  * If aperture state is off we allow use of undefined apertures.
1041  * This happens when gerber files starts, but hasn't decided on
1042  * which aperture to use.
1043  */
1044  if (image->aperture[net->aperture] == NULL) {
1045  /* Commenting this out since it gets emitted every time you click on the screen
1046  if (net->aperture_state != GERBV_APERTURE_STATE_OFF)
1047  GERB_MESSAGE("Aperture D%d is not defined", net->aperture);
1048  */
1049  continue;
1050  }
1051 
1052  /*
1053  * Scale points with window scaling and translate them
1054  */
1055  tempX = net->start_x + sr_x;
1056  tempY = net->start_y + sr_y;
1057  cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
1058  xlong1 = (int)round(tempX);
1059  ylong1 = (int)round(tempY);
1060 
1061  tempX = net->stop_x + sr_x;
1062  tempY = net->stop_y + sr_y;
1063  cairo_matrix_transform_point (&fullMatrix, &tempX, &tempY);
1064  xlong2 = (int)round(tempX);
1065  ylong2 = (int)round(tempY);
1066 
1067  /* if the object is way outside our view window, just skip over it in order
1068  to eliminate some GDK clipping problems at high zoom levels */
1069  if ((xlong1 < -10000) && (xlong2 < -10000))
1070  continue;
1071  if ((ylong1 < -10000) && (ylong2 < -10000))
1072  continue;
1073  if ((xlong1 > 10000) && (xlong2 > 10000))
1074  continue;
1075  if ((ylong1 > 10000) && (ylong2 > 10000))
1076  continue;
1077 
1078  if (xlong1 > G_MAXINT) x1 = G_MAXINT;
1079  else if (xlong1 < G_MININT) x1 = G_MININT;
1080  else x1 = (int)xlong1;
1081 
1082  if (xlong2 > G_MAXINT) x2 = G_MAXINT;
1083  else if (xlong2 < G_MININT) x2 = G_MININT;
1084  else x2 = (int)xlong2;
1085 
1086  if (ylong1 > G_MAXINT) y1 = G_MAXINT;
1087  else if (ylong1 < G_MININT) y1 = G_MININT;
1088  else y1 = (int)ylong1;
1089 
1090  if (ylong2 > G_MAXINT) y2 = G_MAXINT;
1091  else if (ylong2 < G_MININT) y2 = G_MININT;
1092  else y2 = (int)ylong2;
1093 
1094  switch (net->aperture_state) {
1096  tempX = image->aperture[net->aperture]->parameter[0];
1097  cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
1098  p1 = (int)round(tempX);
1099 
1100  // p1 = (int)round(image->aperture[net->aperture]->parameter[0] * scale);
1101  if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE)
1102  gdk_gc_set_line_attributes(gc, p1,
1103  GDK_LINE_SOLID,
1104  GDK_CAP_PROJECTING,
1105  GDK_JOIN_MITER);
1106  else
1107  gdk_gc_set_line_attributes(gc, p1,
1108  GDK_LINE_SOLID,
1109  GDK_CAP_ROUND,
1110  GDK_JOIN_MITER);
1111 
1112  switch (net->interpolation) {
1116  GERB_MESSAGE(_("Linear != x1"));
1117  gdk_gc_set_line_attributes(gc, p1,
1118  GDK_LINE_ON_OFF_DASH,
1119  GDK_CAP_ROUND,
1120  GDK_JOIN_MITER);
1121  gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
1122  gdk_gc_set_line_attributes(gc, p1,
1123  GDK_LINE_SOLID,
1124  GDK_CAP_ROUND,
1125  GDK_JOIN_MITER);
1126  break;
1128  if (image->aperture[net->aperture]->type != GERBV_APTYPE_RECTANGLE)
1129  gdk_draw_line(*pixmap, gc, x1, y1, x2, y2);
1130  else {
1131  gint dx, dy;
1132  GdkPoint poly[6];
1133 
1134  tempX = image->aperture[net->aperture]->parameter[0]/2;
1135  tempY = image->aperture[net->aperture]->parameter[1]/2;
1136  cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
1137  dx = (int)round(tempX);
1138  dy = (int)round(tempY);
1139 
1140  if(x1 > x2) dx = -dx;
1141  if(y1 > y2) dy = -dy;
1142  poly[0].x = x1 - dx; poly[0].y = y1 - dy;
1143  poly[1].x = x1 - dx; poly[1].y = y1 + dy;
1144  poly[2].x = x2 - dx; poly[2].y = y2 + dy;
1145  poly[3].x = x2 + dx; poly[3].y = y2 + dy;
1146  poly[4].x = x2 + dx; poly[4].y = y2 - dy;
1147  poly[5].x = x1 + dx; poly[5].y = y1 - dy;
1148  gdk_draw_polygon(*pixmap, gc, 1, poly, 6);
1149  }
1150  break;
1153  gerbv_gdk_draw_arc(*pixmap, gc, cp_x, cp_y, cir_width, cir_height,
1154  net->cirseg->angle1, net->cirseg->angle2);
1155  break;
1156  default :
1157  break;
1158  }
1159  break;
1161  break;
1163  tempX = image->aperture[net->aperture]->parameter[0];
1164  tempY = image->aperture[net->aperture]->parameter[1];
1165  cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
1166  p1 = (int)round(tempX);
1167  p2 = (int)round(tempY);
1168  tempX = image->aperture[net->aperture]->parameter[2];
1169  cairo_matrix_transform_point (&scaleMatrix, &tempX, &tempY);
1170 
1171  switch (image->aperture[net->aperture]->type) {
1172  case GERBV_APTYPE_CIRCLE :
1173  gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
1174  /*
1175  * If circle has an inner diameter we must remove
1176  * that part of the circle to make a hole in it.
1177  * We should actually support square holes too,
1178  * but due to laziness I don't.
1179  */
1180  if (p2) {
1181  gdk_gc_get_values(gc, &gc_values);
1182  if (gc_values.foreground.pixel == opaque.pixel) {
1183  gdk_gc_set_foreground(gc, &transparent);
1184  gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
1185  gdk_gc_set_foreground(gc, &opaque);
1186  } else {
1187  gdk_gc_set_foreground(gc, &opaque);
1188  gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p2);
1189  gdk_gc_set_foreground(gc, &transparent);
1190  }
1191  }
1192 
1193  break;
1195  gerbv_gdk_draw_rectangle(*pixmap, gc, TRUE, x2, y2, p1, p2);
1196  break;
1197  case GERBV_APTYPE_OVAL :
1198  gerbv_gdk_draw_oval(*pixmap, gc, TRUE, x2, y2, p1, p2);
1199  break;
1200  case GERBV_APTYPE_POLYGON :
1201  gerbv_gdk_draw_circle(*pixmap, gc, TRUE, x2, y2, p1);
1202  break;
1203  case GERBV_APTYPE_MACRO :
1204  gerbv_gdk_draw_amacro(*pixmap, gc,
1205  image->aperture[net->aperture]->simplified,
1206  scale, x2, y2);
1207  break;
1208  default :
1209  GERB_MESSAGE(_("Unknown aperture type"));
1210  return 0;
1211  }
1212  break;
1213  default :
1214  GERB_MESSAGE(_("Unknown aperture state"));
1215  return 0;
1216  }
1217  }
1218  }
1219  }
1220  /*
1221  * Destroy GCs before exiting
1222  */
1223  gdk_gc_unref(gc);
1224  gdk_gc_unref(pgc);
1225 
1226  return 1;
1227 
1228 } /* image2pixmap */
1229 
1230