gerbv
draw.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 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h> /* ceil(), atan2() */
32 
33 #ifdef HAVE_STRING_H
34 # include <string.h>
35 #endif
36 
37 #include "gerbv.h"
38 #include "draw.h"
39 #include "common.h"
40 #include "selection.h"
41 
42 #undef DPRINTF
43 #define DPRINTF(...) do { if (DEBUG) printf(__VA_ARGS__); } while (0)
44 
45 static gboolean draw_do_vector_export_fix(cairo_t *cairoTarget,
46  double *bg_red, double *bg_green, double *bg_blue);
47 
54 void
55 draw_cairo_line_to (cairo_t *cairoTarget, gdouble x, gdouble y,
56  gboolean adjustByHalf, gboolean pixelOutput)
57 {
58  if (pixelOutput) {
59  cairo_user_to_device (cairoTarget, &x, &y);
60  x = round(x);
61  y = round(y);
62  if (adjustByHalf) {
63  x += 0.5;
64  y += 0.5;
65  }
66  cairo_device_to_user (cairoTarget, &x, &y);
67  }
68  cairo_line_to (cairoTarget, x, y);
69 }
70 
77 void
78 draw_cairo_move_to (cairo_t *cairoTarget, gdouble x, gdouble y,
79  gboolean oddWidth, gboolean pixelOutput)
80 {
81  if (pixelOutput) {
82  cairo_user_to_device (cairoTarget, &x, &y);
83  x = round(x);
84  y = round(y);
85  if (oddWidth) {
86  x += 0.5;
87  y += 0.5;
88  }
89  cairo_device_to_user (cairoTarget, &x, &y);
90  }
91  cairo_move_to (cairoTarget, x, y);
92 }
93 
99 void
100 draw_cairo_translate_adjust (cairo_t *cairoTarget, gdouble x, gdouble y,
101  gboolean pixelOutput)
102 {
103  if (pixelOutput) {
104  cairo_user_to_device (cairoTarget, &x, &y);
105  x = round(x);
106  y = round(y);
107  cairo_device_to_user (cairoTarget, &x, &y);
108  }
109 
110  cairo_translate (cairoTarget, x, y);
111 }
112 
119 static gboolean
121  gerbv_selection_info_t *selectionInfo, gboolean remove)
122 {
123  gerbv_selection_item_t sItem;
124 
125  for (guint i = 0; i < selection_length (selectionInfo); i++) {
126  sItem = selection_get_item_by_index (selectionInfo, i);
127  if (sItem.net == net) {
128  if (remove)
129  selection_clear_item_by_index (selectionInfo, i);
130 
131  return TRUE;
132  }
133  }
134 
135  return FALSE;
136 }
137 
138 static void
139 draw_check_if_object_is_in_selected_area (cairo_t *cairoTarget,
140  gboolean isStroke, gerbv_selection_info_t *selectionInfo,
141  gerbv_image_t *image, struct gerbv_net *net,
142  enum draw_mode drawMode)
143 {
144  gerbv_selection_item_t sItem = {image, net};
145  gdouble corner1X, corner1Y, corner2X, corner2Y;
146  gdouble x1, x2, y1, y2;
147  gdouble minX, minY, maxX, maxY;
148 
149  corner1X = selectionInfo->lowerLeftX;
150  corner1Y = selectionInfo->lowerLeftY;
151  corner2X = selectionInfo->upperRightX;
152  corner2Y = selectionInfo->upperRightY;
153 
154  /* calculate the coordinate of the user's click in the current
155  transformation matrix */
156  cairo_device_to_user (cairoTarget, &corner1X, &corner1Y);
157  cairo_device_to_user (cairoTarget, &corner2X, &corner2Y);
158 
159  switch (selectionInfo->type) {
161  /* use the cairo in_fill routine to see if the point is within the
162  drawn area */
163  if ((isStroke && cairo_in_stroke (cairoTarget, corner1X, corner1Y)) ||
164  (!isStroke && cairo_in_fill (cairoTarget, corner1X, corner1Y))) {
165 
167  selectionInfo,
168  (drawMode == FIND_SELECTIONS_TOGGLE))) {
169  selection_add_item (selectionInfo, &sItem);
170  }
171  }
172  break;
173 
175  /* we can't assume the "lowerleft" corner is actually in the lower left,
176  since the cairo transformation matrix may be mirrored,etc */
177  minX = MIN(corner1X,corner2X);
178  maxX = MAX(corner1X,corner2X);
179  minY = MIN(corner1Y,corner2Y);
180  maxY = MAX(corner1Y,corner2Y);
181 
182  if (isStroke)
183  cairo_stroke_extents (cairoTarget, &x1, &y1, &x2, &y2);
184  else
185  cairo_fill_extents (cairoTarget, &x1, &y1, &x2, &y2);
186 
187  if ((minX < x1) && (minY < y1) && (maxX > x2) && (maxY > y2)) {
189  selectionInfo,
190  (drawMode == FIND_SELECTIONS_TOGGLE))) {
191  selection_add_item (selectionInfo, &sItem);
192  }
193  }
194  break;
195  default:
196  break;
197  }
198  /* clear the path, since we didn't actually draw it and cairo
199  doesn't reset it after the previous calls */
200  cairo_new_path (cairoTarget);
201 }
202 
203 static void
204 draw_fill (cairo_t *cairoTarget, enum draw_mode drawMode,
205  gerbv_selection_info_t *selectionInfo,
206  gerbv_image_t *image, struct gerbv_net *net)
207 {
208  if ((drawMode == DRAW_IMAGE) || (drawMode == DRAW_SELECTIONS))
209  cairo_fill (cairoTarget);
210  else
211  draw_check_if_object_is_in_selected_area (cairoTarget, FALSE,
212  selectionInfo, image, net, drawMode);
213 }
214 
215 static void
216 draw_stroke (cairo_t *cairoTarget, enum draw_mode drawMode,
217  gerbv_selection_info_t *selectionInfo,
218  gerbv_image_t *image, struct gerbv_net *net)
219 {
220  if ((drawMode == DRAW_IMAGE) || (drawMode == DRAW_SELECTIONS))
221  cairo_stroke (cairoTarget);
222  else
223  draw_check_if_object_is_in_selected_area (cairoTarget, TRUE,
224  selectionInfo, image, net, drawMode);
225 }
226 
230 static void
231 gerbv_draw_circle(cairo_t *cairoTarget, gdouble diameter)
232 {
233  cairo_arc (cairoTarget, 0.0, 0.0, diameter/2.0, 0, 2.0*M_PI);
234 
235  return;
236 }
237 
243 static void
244 gerbv_draw_rectangle(cairo_t *cairoTarget, gdouble width, gdouble height,
245  gboolean pixelOutput)
246 {
247  if (pixelOutput) {
248  cairo_user_to_device_distance (cairoTarget, &width, &height);
249  width -= (int)round(width) % 2;
250  height -= (int)round(height) % 2;
251  cairo_device_to_user_distance (cairoTarget, &width, &height);
252  }
253 
254  cairo_rectangle (cairoTarget, -width/2.0, -height/2.0, width, height);
255 
256  return;
257 }
258 
263 static void
264 gerbv_draw_oblong(cairo_t *cairoTarget, gdouble width, gdouble height)
265 {
266  /* --- This stuff produces a line + rounded ends --- */
267  gdouble circleDiameter, strokeDistance;
268 
269  cairo_new_path (cairoTarget);
270  if (width < height) {
271  circleDiameter = width;
272  strokeDistance = (height - width)/2.0;
273  cairo_arc (cairoTarget, 0.0, strokeDistance, circleDiameter/2.0, 0, -M_PI);
274  cairo_line_to (cairoTarget, -circleDiameter/2.0, -strokeDistance);
275  cairo_arc (cairoTarget, 0.0, -strokeDistance, circleDiameter/2.0, -M_PI, 0);
276  cairo_line_to (cairoTarget, circleDiameter/2.0, strokeDistance);
277  } else {
278  circleDiameter = height;
279  strokeDistance = (width - height)/2.0;
280  cairo_arc (cairoTarget, -strokeDistance, 0.0,
281  circleDiameter/2.0, M_PI_2, -M_PI_2);
282  cairo_line_to (cairoTarget, strokeDistance,
283  -circleDiameter/2.0);
284  cairo_arc (cairoTarget, strokeDistance, 0.0,
285  circleDiameter/2.0, -M_PI_2, M_PI_2);
286  cairo_line_to (cairoTarget, -strokeDistance,
287  circleDiameter/2.0);
288  }
289 
290 #if 0
291  /* --- This stuff produces an oval pad --- */
292  /* cairo doesn't have a function to draw ovals, so we must
293  * draw an arc and stretch it by scaling different x and y values */
294  cairo_save (cairoTarget);
295  cairo_scale (cairoTarget, width, height);
296  gerbv_draw_circle (cairoTarget, 1);
297  cairo_restore (cairoTarget);
298 #endif
299  return;
300 }
301 
302 static void
303 gerbv_draw_polygon(cairo_t *cairoTarget, gdouble outsideDiameter,
304  gdouble numberOfSides, gdouble degreesOfRotation)
305 {
306  int i, numberOfSidesInteger = (int) numberOfSides;
307 
308  cairo_rotate(cairoTarget, DEG2RAD(degreesOfRotation));
309  cairo_move_to(cairoTarget, outsideDiameter / 2.0, 0);
310 
311  /* skip first point, since we've moved there already */
312  for (i = 1; i < numberOfSidesInteger; i++){
313  gdouble angle = ((double)i)*M_PI*2.0 / numberOfSidesInteger;
314  cairo_line_to (cairoTarget, cos(angle) * outsideDiameter / 2.0,
315  sin(angle) * outsideDiameter / 2.0);
316  }
317 
318  return;
319 }
320 
321 
322 static void
323 gerbv_draw_aperture_hole(cairo_t *cairoTarget,
324  gdouble dimensionX, gdouble dimensionY, gboolean pixelOutput)
325 {
326  if (dimensionX) {
327  cairo_new_sub_path (cairoTarget);
328  if (dimensionY)
329  gerbv_draw_rectangle (cairoTarget,
330  dimensionX, dimensionY, pixelOutput);
331  else
332  gerbv_draw_circle (cairoTarget, dimensionX);
333  }
334 
335  return;
336 }
337 
338 static void
339 draw_update_macro_exposure (cairo_t *cairoTarget, cairo_operator_t clearOperator,
340  cairo_operator_t darkOperator, gdouble exposureSetting){
341 
342  if (exposureSetting == 0.0) {
343  cairo_set_operator (cairoTarget, clearOperator);
344  } else if (exposureSetting == 1.0) {
345  cairo_set_operator (cairoTarget, darkOperator);
346  } else if (exposureSetting == 2.0) {
347  /* reverse current exposure setting */
348  cairo_operator_t currentOperator = cairo_get_operator (cairoTarget);
349  if (currentOperator == clearOperator) {
350  cairo_set_operator (cairoTarget, darkOperator);
351  } else {
352  cairo_set_operator (cairoTarget, clearOperator);
353  }
354  }
355 }
356 
357 
358 static int
359 gerbv_draw_amacro(cairo_t *cairoTarget, cairo_operator_t clearOperator,
360  cairo_operator_t darkOperator, gerbv_simplified_amacro_t *s,
361  gint usesClearPrimitive, gdouble pixelWidth, enum draw_mode drawMode,
362  gerbv_selection_info_t *selectionInfo,
363  gerbv_image_t *image, struct gerbv_net *net)
364 {
365  gerbv_simplified_amacro_t *ls = s;
366  gboolean doVectorExportFix;
367  double bg_r, bg_g, bg_b; /* Background color */
368  int ret = 1;
369 
370  DPRINTF("Drawing simplified aperture macros:\n");
371 
372  doVectorExportFix =
373  draw_do_vector_export_fix (cairoTarget, &bg_r, &bg_g, &bg_b);
374 
375  switch (cairo_surface_get_type (cairo_get_target (cairoTarget))) {
376 
377  case CAIRO_SURFACE_TYPE_PDF:
378  case CAIRO_SURFACE_TYPE_PS:
379  case CAIRO_SURFACE_TYPE_SVG:
380 
381  /* Don't limit "pixel width" in vector export */
382  pixelWidth = DBL_MIN;
383 
384  break;
385 
386  default:
387  break;
388  }
389 
390  if (usesClearPrimitive)
391  cairo_push_group (cairoTarget);
392 
393  while (ls != NULL) {
394  /*
395  * This handles the exposure thing in the aperture macro
396  * The exposure is always the first element on stack independent
397  * of aperture macro.
398  */
399  cairo_save (cairoTarget);
400  cairo_new_path(cairoTarget);
401 
402  DPRINTF("\t%s(): drawing %s\n", __FUNCTION__,
403  gerbv_aperture_type_name(ls->type));
404 
405  switch (ls->type) {
406 
408  draw_update_macro_exposure (cairoTarget,
409  clearOperator, darkOperator,
410  ls->parameter[CIRCLE_EXPOSURE]);
411  cairo_rotate (cairoTarget, DEG2RAD(
412  ls->parameter[CIRCLE_ROTATION]));
413  cairo_translate (cairoTarget,
414  ls->parameter[CIRCLE_CENTER_X],
415  ls->parameter[CIRCLE_CENTER_Y]);
416  gerbv_draw_circle (cairoTarget,
417  ls->parameter[CIRCLE_DIAMETER]);
418 
419  if (doVectorExportFix
420  && CAIRO_OPERATOR_CLEAR ==
421  cairo_get_operator (cairoTarget)) {
422  cairo_save (cairoTarget);
423  cairo_set_source_rgba (cairoTarget,
424  bg_r, bg_g, bg_b, 1.0);
425  cairo_set_operator (cairoTarget,
426  CAIRO_OPERATOR_OVER);
427 
428  draw_fill (cairoTarget, drawMode,
429  selectionInfo, image, net);
430 
431  cairo_restore (cairoTarget);
432 
433  break;
434  }
435 
436  draw_fill (cairoTarget, drawMode,
437  selectionInfo, image, net);
438  break;
439 
441  draw_update_macro_exposure (cairoTarget,
442  clearOperator, darkOperator,
443  ls->parameter[OUTLINE_EXPOSURE]);
444  cairo_rotate (cairoTarget, DEG2RAD(ls->parameter[
445  OUTLINE_ROTATION_IDX(ls->parameter)]));
446  cairo_move_to (cairoTarget,
447  ls->parameter[OUTLINE_FIRST_X],
448  ls->parameter[OUTLINE_FIRST_Y]);
449 
450  for (int point = 1; point <
451  1 + (int)ls->parameter[
452  OUTLINE_NUMBER_OF_POINTS];
453  point++) {
454  cairo_line_to (cairoTarget,
455  ls->parameter[OUTLINE_X_IDX_OF_POINT(
456  point)],
457  ls->parameter[OUTLINE_Y_IDX_OF_POINT(
458  point)]);
459  }
460 
461  if (doVectorExportFix
462  && CAIRO_OPERATOR_CLEAR ==
463  cairo_get_operator (cairoTarget)) {
464  cairo_save (cairoTarget);
465  cairo_set_source_rgba (cairoTarget,
466  bg_r, bg_g, bg_b, 1.0);
467  cairo_set_operator (cairoTarget,
468  CAIRO_OPERATOR_OVER);
469 
470  draw_fill (cairoTarget, drawMode,
471  selectionInfo, image, net);
472 
473  cairo_restore (cairoTarget);
474 
475  break;
476  }
477 
478  /* Although the gerber specs allow for an open outline,
479  * I interpret it to mean the outline should be closed
480  * by the rendering softare automatically, since there
481  * is no dimension for line thickness. */
482  draw_fill (cairoTarget, drawMode,
483  selectionInfo, image, net);
484  break;
485 
487  draw_update_macro_exposure (cairoTarget,
488  clearOperator, darkOperator,
489  ls->parameter[POLYGON_EXPOSURE]);
490  cairo_translate (cairoTarget,
491  ls->parameter[POLYGON_CENTER_X],
492  ls->parameter[POLYGON_CENTER_Y]);
493  gerbv_draw_polygon(cairoTarget,
494  ls->parameter[POLYGON_DIAMETER],
495  ls->parameter[POLYGON_NUMBER_OF_POINTS],
496  ls->parameter[POLYGON_ROTATION]);
497 
498  if (doVectorExportFix
499  && CAIRO_OPERATOR_CLEAR ==
500  cairo_get_operator (cairoTarget)) {
501  cairo_save (cairoTarget);
502  cairo_set_source_rgba (cairoTarget,
503  bg_r, bg_g, bg_b, 1.0);
504  cairo_set_operator (cairoTarget,
505  CAIRO_OPERATOR_OVER);
506 
507  draw_fill (cairoTarget, drawMode,
508  selectionInfo, image, net);
509 
510  cairo_restore (cairoTarget);
511 
512  break;
513  }
514 
515  draw_fill (cairoTarget, drawMode,
516  selectionInfo, image, net);
517  break;
518 
520  gdouble diameter, diameterDifference, crosshairRadius;
521 
522  cairo_translate (cairoTarget,
523  ls->parameter[MOIRE_CENTER_X],
524  ls->parameter[MOIRE_CENTER_Y]);
525  cairo_rotate (cairoTarget,
526  DEG2RAD(ls->parameter[MOIRE_ROTATION]));
527  diameter = ls->parameter[MOIRE_OUTSIDE_DIAMETER]
528  - ls->parameter[MOIRE_CIRCLE_THICKNESS];
529  diameterDifference = 2*(ls->parameter[MOIRE_GAP_WIDTH]
530  + ls->parameter[MOIRE_CIRCLE_THICKNESS]);
531  cairo_set_line_width (cairoTarget,
532  ls->parameter[MOIRE_CIRCLE_THICKNESS]);
533 
534  if (doVectorExportFix
535  && CAIRO_OPERATOR_CLEAR ==
536  cairo_get_operator (cairoTarget)) {
537  cairo_save (cairoTarget);
538  cairo_set_source_rgba (cairoTarget,
539  bg_r, bg_g, bg_b, 1.0);
540  cairo_set_operator (cairoTarget,
541  CAIRO_OPERATOR_OVER);
542  }
543 
544  for (int circle = 0; circle < (int)ls->parameter[
545  MOIRE_NUMBER_OF_CIRCLES]; circle++) {
546  gdouble dia =
547  diameter - diameterDifference * circle;
548 
549  if (dia <= 0) {
550  GERB_COMPILE_WARNING (_("Ignoring %s "
551  "with non positive diameter"),
553  ls->type));
554  continue;
555  }
556 
557  gerbv_draw_circle (cairoTarget, dia);
558  draw_stroke (cairoTarget, drawMode,
559  selectionInfo, image, net);
560  }
561 
562 
563  cairo_set_line_width (cairoTarget,
564  ls->parameter[MOIRE_CROSSHAIR_THICKNESS]);
565  crosshairRadius =
566  ls->parameter[MOIRE_CROSSHAIR_LENGTH] / 2.0;
567  cairo_move_to (cairoTarget, -crosshairRadius, 0);
568  cairo_line_to (cairoTarget, crosshairRadius, 0);
569  cairo_move_to (cairoTarget, 0, -crosshairRadius);
570  cairo_line_to (cairoTarget, 0, crosshairRadius);
571 
572  draw_stroke (cairoTarget, drawMode,
573  selectionInfo, image, net);
574 
575  if (doVectorExportFix
576  && CAIRO_OPERATOR_CLEAR ==
577  cairo_get_operator (cairoTarget)) {
578  cairo_restore (cairoTarget);
579  }
580 
581  break;
582  }
584  gdouble startAngle1, startAngle2, endAngle1, endAngle2;
585 
586  cairo_translate (cairoTarget,
587  ls->parameter[THERMAL_CENTER_X],
588  ls->parameter[THERMAL_CENTER_Y]);
589  cairo_rotate (cairoTarget,
590  DEG2RAD(ls->parameter[THERMAL_ROTATION]));
591  startAngle1 = asin (
592  ls->parameter[THERMAL_CROSSHAIR_THICKNESS]/
593  ls->parameter[THERMAL_INSIDE_DIAMETER]);
594  endAngle1 = M_PI_2 - startAngle1;
595  endAngle2 = asin (
596  ls->parameter[THERMAL_CROSSHAIR_THICKNESS]/
597  ls->parameter[THERMAL_OUTSIDE_DIAMETER]);
598  startAngle2 = M_PI_2 - endAngle2;
599 
600  if (doVectorExportFix
601  && CAIRO_OPERATOR_CLEAR ==
602  cairo_get_operator (cairoTarget)) {
603  cairo_save (cairoTarget);
604  cairo_set_source_rgba (cairoTarget,
605  bg_r, bg_g, bg_b, 1.0);
606  cairo_set_operator (cairoTarget,
607  CAIRO_OPERATOR_OVER);
608 
609  /* */
610 
611  cairo_restore (cairoTarget);
612 
613  break;
614  }
615 
616  for (gint i = 0; i < 4; i++) {
617  cairo_arc (cairoTarget, 0, 0,
618  ls->parameter[
619  THERMAL_INSIDE_DIAMETER]/2.0,
620  startAngle1, endAngle1);
621  cairo_arc_negative (cairoTarget, 0, 0,
622  ls->parameter[
623  THERMAL_OUTSIDE_DIAMETER]/2.0,
624  startAngle2, endAngle2);
625  draw_fill (cairoTarget,
626  drawMode, selectionInfo,
627  image, net);
628  cairo_rotate (cairoTarget, M_PI_2);
629  }
630 
631  break;
632  }
634  draw_update_macro_exposure (cairoTarget,
635  clearOperator, darkOperator,
636  ls->parameter[LINE20_EXPOSURE]);
637  cairo_set_line_width (cairoTarget,
638  MAX(ls->parameter[LINE20_LINE_WIDTH],
639  pixelWidth));
640  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_BUTT);
641  cairo_rotate (cairoTarget, DEG2RAD(
642  ls->parameter[LINE20_ROTATION]));
643  cairo_move_to (cairoTarget,
644  ls->parameter[LINE20_START_X],
645  ls->parameter[LINE20_START_Y]);
646  cairo_line_to (cairoTarget,
647  ls->parameter[LINE20_END_X],
648  ls->parameter[LINE20_END_Y]);
649 
650  if (doVectorExportFix
651  && CAIRO_OPERATOR_CLEAR ==
652  cairo_get_operator (cairoTarget)) {
653  cairo_save (cairoTarget);
654  cairo_set_source_rgba (cairoTarget,
655  bg_r, bg_g, bg_b, 1.0);
656  cairo_set_operator (cairoTarget,
657  CAIRO_OPERATOR_OVER);
658 
659  draw_stroke (cairoTarget, drawMode,
660  selectionInfo, image, net);
661 
662  cairo_restore (cairoTarget);
663 
664  break;
665  }
666 
667  draw_stroke (cairoTarget, drawMode,
668  selectionInfo, image, net);
669  break;
670 
672  draw_update_macro_exposure (cairoTarget,
673  clearOperator, darkOperator,
674  ls->parameter[LINE21_EXPOSURE]);
675  cairo_rotate (cairoTarget, DEG2RAD(
676  ls->parameter[LINE21_ROTATION]));
677  cairo_translate (cairoTarget,
678  ls->parameter[LINE21_CENTER_X],
679  ls->parameter[LINE21_CENTER_Y]);
680  cairo_rectangle (cairoTarget,
681  -MAX(ls->parameter[LINE21_WIDTH]/2.0,
682  pixelWidth),
683  -MAX(ls->parameter[LINE21_HEIGHT]/2.0,
684  pixelWidth),
685  MAX(ls->parameter[LINE21_WIDTH],
686  pixelWidth),
687  MAX(ls->parameter[LINE21_HEIGHT],
688  pixelWidth));
689  if (doVectorExportFix
690  && CAIRO_OPERATOR_CLEAR ==
691  cairo_get_operator (cairoTarget)) {
692  cairo_save (cairoTarget);
693  cairo_set_source_rgba (cairoTarget,
694  bg_r, bg_g, bg_b, 1.0);
695  cairo_set_operator (cairoTarget,
696  CAIRO_OPERATOR_OVER);
697 
698  draw_fill (cairoTarget, drawMode,
699  selectionInfo, image, net);
700 
701  cairo_restore (cairoTarget);
702 
703  break;
704  }
705 
706  draw_fill (cairoTarget, drawMode,
707  selectionInfo, image, net);
708  break;
709 
711  draw_update_macro_exposure (cairoTarget,
712  clearOperator, darkOperator,
713  ls->parameter[LINE22_EXPOSURE]);
714  cairo_rotate (cairoTarget, DEG2RAD(
715  ls->parameter[LINE22_ROTATION]));
716  cairo_translate (cairoTarget,
717  ls->parameter[LINE22_LOWER_LEFT_X],
718  ls->parameter[LINE22_LOWER_LEFT_Y]);
719  cairo_rectangle (cairoTarget, 0, 0,
720  MAX(ls->parameter[LINE22_WIDTH],
721  pixelWidth),
722  MAX(ls->parameter[LINE22_HEIGHT],
723  pixelWidth));
724 
725  if (doVectorExportFix
726  && CAIRO_OPERATOR_CLEAR ==
727  cairo_get_operator (cairoTarget)) {
728  cairo_save (cairoTarget);
729  cairo_set_source_rgba (cairoTarget,
730  bg_r, bg_g, bg_b, 1.0);
731  cairo_set_operator (cairoTarget,
732  CAIRO_OPERATOR_OVER);
733 
734  draw_fill (cairoTarget, drawMode,
735  selectionInfo, image, net);
736 
737  cairo_restore (cairoTarget);
738 
739  break;
740  }
741 
742  draw_fill (cairoTarget, drawMode,
743  selectionInfo, image, net);
744  break;
745 
746  default:
747  GERB_COMPILE_WARNING(_("Unknown macro type: %s"),
748  gerbv_aperture_type_name(ls->type));
749  ret = 0;
750  }
751 
752  cairo_restore (cairoTarget);
753  ls = ls->next;
754  }
755 
756  if (usesClearPrimitive) {
757  cairo_pop_group_to_source (cairoTarget);
758  cairo_paint (cairoTarget);
759  }
760 
761  return ret;
762 }
763 
764 void
765 draw_apply_netstate_transformation (cairo_t *cairoTarget, gerbv_netstate_t *state)
766 {
767  /* Gerber X2 §4.9 transformation order applied to a point:
768  * Scale (LS) → Rotate (LR) → Mirror (LM).
769  *
770  * Cairo left-multiplies — each call computes CTM_new = M_new × CTM_old —
771  * so the call order is the reverse of the coordinate-space order. To
772  * land at CTM = M_lm × R_lr × T_of × S_ls, the Cairo calls must run
773  * scale → translate → rotate → mirror (this order).
774  *
775  * apply scale factor */
776  cairo_scale (cairoTarget, state->scaleA, state->scaleB);
777  /* apply offset */
778  cairo_translate (cairoTarget, state->offsetA, state->offsetB);
779  /* apply per-object rotation (LR command) — must precede the mirror
780  * switch so the spec's Scale→Rotate→Mirror order holds. Calling
781  * cairo_rotate AFTER the mirror would compose as R∘M instead of
782  * M∘R, which renders correctly only when no LM is active. */
783  if (state->rotation != 0.0) {
784  cairo_rotate (cairoTarget, state->rotation);
785  }
786  /* apply mirror */
787  switch (state->mirrorState) {
788  case GERBV_MIRROR_STATE_FLIPA:
789  cairo_scale (cairoTarget, -1, 1);
790  break;
791  case GERBV_MIRROR_STATE_FLIPB:
792  cairo_scale (cairoTarget, 1, -1);
793  break;
794  case GERBV_MIRROR_STATE_FLIPAB:
795  cairo_scale (cairoTarget, -1, -1);
796  break;
797  default:
798  break;
799  }
800  /* finally, apply axis select */
801  if (state->axisSelect == GERBV_AXIS_SELECT_SWAPAB) {
802  /* we do this by rotating 270 (counterclockwise, then mirroring
803  the Y axis */
804  cairo_rotate (cairoTarget, M_PI + M_PI_2);
805  cairo_scale (cairoTarget, 1, -1);
806  }
807 }
808 
809 void
810 draw_render_polygon_object (gerbv_net_t *oldNet, cairo_t *cairoTarget,
811  gdouble sr_x, gdouble sr_y, gerbv_image_t *image,
812  enum draw_mode drawMode, gerbv_selection_info_t *selectionInfo,
813  gboolean pixelOutput)
814 {
815  gerbv_net_t *currentNet, *polygonStartNet;
816  int haveDrawnFirstFillPoint = 0;
817  gdouble x2,y2,cp_x=0,cp_y=0;
818 
819  haveDrawnFirstFillPoint = FALSE;
820  /* save the first net in the polygon as the "ID" net pointer
821  in case we are saving this net to the selection array */
822  polygonStartNet = oldNet;
823  cairo_new_path(cairoTarget);
824 
825  for (currentNet = oldNet->next; currentNet!=NULL;
826  currentNet = currentNet->next) {
827  x2 = currentNet->stop_x + sr_x;
828  y2 = currentNet->stop_y + sr_y;
829 
830  /* translate circular x,y data as well */
831  if (currentNet->cirseg) {
832  cp_x = currentNet->cirseg->cp_x + sr_x;
833  cp_y = currentNet->cirseg->cp_y + sr_y;
834  }
835  if (!haveDrawnFirstFillPoint) {
836  draw_cairo_move_to (cairoTarget, x2, y2, FALSE, pixelOutput);
837  haveDrawnFirstFillPoint=TRUE;
838  continue;
839  }
840 
841  switch (currentNet->interpolation) {
846  draw_cairo_line_to (cairoTarget, x2, y2, FALSE, pixelOutput);
847  break;
850  if (currentNet->cirseg->angle2 > currentNet->cirseg->angle1) {
851  cairo_arc (cairoTarget, cp_x, cp_y, currentNet->cirseg->width/2.0,
852  DEG2RAD(currentNet->cirseg->angle1),
853  DEG2RAD(currentNet->cirseg->angle2));
854  } else {
855  cairo_arc_negative (cairoTarget, cp_x, cp_y, currentNet->cirseg->width/2.0,
856  DEG2RAD(currentNet->cirseg->angle1),
857  DEG2RAD(currentNet->cirseg->angle2));
858  }
859  break;
861  cairo_close_path(cairoTarget);
862  /* turn off anti-aliasing for polygons, since it shows seams
863  with adjacent polygons (usually on PCB ground planes) */
864  cairo_antialias_t oldAlias = cairo_get_antialias (cairoTarget);
865  cairo_set_antialias (cairoTarget, CAIRO_ANTIALIAS_NONE);
866  draw_fill (cairoTarget, drawMode, selectionInfo, image, polygonStartNet);
867  cairo_set_antialias (cairoTarget, oldAlias);
868  return;
869  default :
870  break;
871  }
872  }
873 }
874 
880 static void
881 draw_cairo_cross (cairo_t *cairoTarget, gdouble xc, gdouble yc, gdouble r)
882 {
883  cairo_move_to (cairoTarget, xc, yc - r);
884  cairo_rel_line_to (cairoTarget, 0, 2*r);
885  cairo_move_to (cairoTarget, xc - r, yc);
886  cairo_rel_line_to (cairoTarget, 2*r, 0);
887  cairo_stroke (cairoTarget);
888 }
889 
890 static int
891 draw_calc_pnp_mark_coords(struct gerbv_net *start_net,
892  double *label_x, double *label_y)
893 {
894  double x, y;
895  struct gerbv_net *net = start_net;
896  const char *label = NULL;
897 
898  if (net && net->label)
899  label = net->label->str;
900 
901  if (label == NULL)
902  return 0;
903 
904  x = HUGE_VAL; y = -HUGE_VAL;
905  do {
906  if (!net->label
907  || 0 != g_strcmp0 (net->label->str, label))
908  break;
909 
910  /* Search top left corner */
911  if (net->boundingBox.top != HUGE_VAL) {
912  /* Bounding box not calculated */
913  x = MIN(x, net->boundingBox.left);
914  y = MAX(y, net->boundingBox.top);
915  } else {
916  x = MIN(x, net->stop_x);
917  y = MAX(y, net->stop_y + 0.01/2);
918  /* 0.01 default line width */
919  }
920  } while (NULL !=
922 
923  *label_x = x;
924  *label_y = y;
925 
926  return 1;
927 }
928 
949 static void
950 draw_render_block_nets (cairo_t *cairoTarget, gerbv_image_t *image,
951  gerbv_net_t *block_netlist, gerbv_net_t *flash_net,
952  enum draw_mode drawMode, gerbv_selection_info_t *selectionInfo,
953  gboolean pixelOutput, gdouble pixelWidth, gdouble lineWidth,
954  cairo_operator_t drawOperatorClear, cairo_operator_t drawOperatorDark)
955 {
956  gerbv_net_t *block_net;
957  gdouble bx1, by1, bx2, by2;
958 
959  for (block_net = block_netlist->next;
960  block_net != NULL;
961  block_net = block_net->next) {
962 
963  /* 1. Polygon regions — must be checked first (aperture_state is OFF) */
965  draw_render_polygon_object (block_net, cairoTarget,
966  0, 0, image, drawMode, selectionInfo, pixelOutput);
967  /* Advance past PAREA_END */
968  while (block_net->next != NULL &&
969  block_net->next->interpolation !=
971  block_net = block_net->next;
972  if (block_net->next != NULL)
973  block_net = block_net->next;
974  continue;
975  }
976 
977  bx1 = block_net->start_x;
978  by1 = block_net->start_y;
979  bx2 = block_net->stop_x;
980  by2 = block_net->stop_y;
981 
982  if (block_net->aperture_state == GERBV_APERTURE_STATE_ON) {
983  cairo_set_line_width (cairoTarget,
984  image->aperture[block_net->aperture] ?
985  image->aperture[block_net->aperture]->parameter[0] :
986  lineWidth);
987 
988  /* 2. Rectangle draw strokes — filled quad */
989  if (image->aperture[block_net->aperture] &&
990  image->aperture[block_net->aperture]->type ==
992  gdouble dx = image->aperture[block_net->aperture]->parameter[0] / 2;
993  gdouble dy = image->aperture[block_net->aperture]->parameter[1] / 2;
994  if (bx1 > bx2) dx = -dx;
995  if (by1 > by2) dy = -dy;
996  cairo_new_path (cairoTarget);
997  draw_cairo_move_to (cairoTarget, bx1 - dx, by1 - dy, FALSE, pixelOutput);
998  draw_cairo_line_to (cairoTarget, bx1 - dx, by1 + dy, FALSE, pixelOutput);
999  draw_cairo_line_to (cairoTarget, bx2 - dx, by2 + dy, FALSE, pixelOutput);
1000  draw_cairo_line_to (cairoTarget, bx2 + dx, by2 + dy, FALSE, pixelOutput);
1001  draw_cairo_line_to (cairoTarget, bx2 + dx, by2 - dy, FALSE, pixelOutput);
1002  draw_cairo_line_to (cairoTarget, bx1 + dx, by1 - dy, FALSE, pixelOutput);
1003  draw_fill (cairoTarget, drawMode, selectionInfo, image, flash_net);
1004  }
1005  /* 3. Arc strokes (CW/CCW circular interpolation) */
1006  else if (block_net->cirseg != NULL &&
1009  cairo_new_path (cairoTarget);
1010  if (image->aperture[block_net->aperture] &&
1011  image->aperture[block_net->aperture]->type ==
1013  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE);
1014  else
1015  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1016  cairo_save (cairoTarget);
1017  cairo_translate (cairoTarget,
1018  block_net->cirseg->cp_x, block_net->cirseg->cp_y);
1019  cairo_scale (cairoTarget,
1020  block_net->cirseg->width, block_net->cirseg->height);
1021  if (block_net->cirseg->angle2 > block_net->cirseg->angle1)
1022  cairo_arc (cairoTarget, 0.0, 0.0, 0.5,
1023  DEG2RAD(block_net->cirseg->angle1),
1024  DEG2RAD(block_net->cirseg->angle2));
1025  else
1026  cairo_arc_negative (cairoTarget, 0.0, 0.0, 0.5,
1027  DEG2RAD(block_net->cirseg->angle1),
1028  DEG2RAD(block_net->cirseg->angle2));
1029  cairo_restore (cairoTarget);
1030  draw_stroke (cairoTarget, drawMode, selectionInfo, image, flash_net);
1031  }
1032  /* 4. Linear draw — round cap line */
1033  else {
1034  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1035  cairo_new_path (cairoTarget);
1036  draw_cairo_move_to (cairoTarget, bx1, by1, FALSE, pixelOutput);
1037  draw_cairo_line_to (cairoTarget, bx2, by2, FALSE, pixelOutput);
1038  draw_stroke (cairoTarget, drawMode, selectionInfo, image, flash_net);
1039  }
1040  } else if (block_net->aperture_state == GERBV_APERTURE_STATE_FLASH) {
1041  if (block_net->aperture >= 0 &&
1042  image->aperture[block_net->aperture] != NULL) {
1043  gdouble *bp =
1044  image->aperture[block_net->aperture]->parameter;
1045  /* Mirrors skip_shared_fill in draw_image_to_cairo_target():
1046  * MACRO and BLOCK do their own fills internally, so we
1047  * must not run draw_fill() on the empty current path
1048  * afterwards. The simple-aperture cases still need it
1049  * because gerbv_draw_circle/rectangle/oblong/polygon only
1050  * build the cairo path. */
1051  gboolean skip_shared_fill = FALSE;
1052 
1053  cairo_save (cairoTarget);
1054  draw_cairo_translate_adjust (cairoTarget,
1055  bx2, by2, pixelOutput);
1056  switch (image->aperture[block_net->aperture]->type) {
1057  case GERBV_APTYPE_CIRCLE:
1058  gerbv_draw_circle (cairoTarget, bp[0]);
1059  /* Aperture hole (CxHxH form). Same as the main
1060  * draw_image_to_cairo_target() flash path; without
1061  * it, a holed circle in a block renders as a solid
1062  * disc instead of an annulus (PCB padstacks). */
1063  gerbv_draw_aperture_hole (cairoTarget,
1064  bp[1], bp[2], pixelOutput);
1065  break;
1067  gerbv_draw_rectangle (cairoTarget,
1068  bp[0], bp[1], pixelOutput);
1069  gerbv_draw_aperture_hole (cairoTarget,
1070  bp[2], bp[3], pixelOutput);
1071  break;
1072  case GERBV_APTYPE_OVAL:
1073  gerbv_draw_oblong (cairoTarget, bp[0], bp[1]);
1074  gerbv_draw_aperture_hole (cairoTarget,
1075  bp[2], bp[3], pixelOutput);
1076  break;
1077  case GERBV_APTYPE_POLYGON:
1078  gerbv_draw_polygon (cairoTarget,
1079  bp[0], bp[1], bp[2]);
1080  gerbv_draw_aperture_hole (cairoTarget,
1081  bp[3], bp[4], pixelOutput);
1082  break;
1083  case GERBV_APTYPE_MACRO:
1084  gerbv_draw_amacro (cairoTarget,
1085  drawOperatorClear, drawOperatorDark,
1086  image->aperture[block_net->aperture]->simplified,
1087  (gint)bp[0],
1088  pixelWidth, drawMode, selectionInfo,
1089  image, flash_net);
1090  skip_shared_fill = TRUE;
1091  break;
1092  case GERBV_APTYPE_BLOCK:
1093  /* Parser rejects nested AB today (gerber.c
1094  * A2I('A','B') open handler), so this branch
1095  * is unreachable from real input. Kept for
1096  * forward-compat with a future stacked parser. */
1097  draw_render_block_nets (cairoTarget, image,
1098  image->aperture[block_net->aperture]->block_netlist,
1099  flash_net, drawMode, selectionInfo,
1100  pixelOutput, pixelWidth, lineWidth,
1101  drawOperatorClear, drawOperatorDark);
1102  skip_shared_fill = TRUE;
1103  break;
1104  default:
1105  break;
1106  }
1107  if (!skip_shared_fill)
1108  draw_fill (cairoTarget, drawMode,
1109  selectionInfo, image, flash_net);
1110  cairo_restore (cairoTarget);
1111  }
1112  }
1113  }
1114 }
1115 
1116 int
1117 draw_image_to_cairo_target (cairo_t *cairoTarget, gerbv_image_t *image,
1118  gdouble pixelWidth, enum draw_mode drawMode,
1119  gerbv_selection_info_t *selectionInfo,
1120  gerbv_render_info_t *renderInfo, gboolean allowOptimization,
1121  gerbv_user_transformation_t transform, gboolean pixelOutput)
1122 {
1123  const int hole_cross_inc_px = 8;
1124  struct gerbv_net *net, *polygonStartNet=NULL;
1125  double x1, y1, x2, y2, cp_x=0, cp_y=0;
1126  gdouble *p, p0, p1, dx, dy, lineWidth, r;
1127  gerbv_netstate_t *oldState;
1128  gerbv_layer_t *oldLayer;
1129  cairo_operator_t drawOperatorClear, drawOperatorDark;
1130  gboolean invertPolarity = FALSE, oddWidth = FALSE;
1131  gdouble minX=0, minY=0, maxX=0, maxY=0;
1132  gdouble criticalRadius;
1133  gdouble scaleX = transform.scaleX;
1134  gdouble scaleY = transform.scaleY;
1135  /* Keep PNP label not mirrored */
1136  gdouble pnp_label_scale_x = 1, pnp_label_scale_y= -1;
1137  gboolean limitLineWidth = TRUE;
1138  gboolean displayPixel = TRUE;
1139  gboolean doVectorExportFix;
1140  /* Initialize so GCC's -Wmaybe-uninitialized doesn't fire under -Werror
1141  * on the bg_r/bg_g/bg_b use below: those are only read inside the
1142  * `if (doVectorExportFix && ...)` guard at the trailing fill, but the
1143  * compiler can't always see that draw_do_vector_export_fix() writes
1144  * through the pointers in the FALSE return path. Defaulting to 0
1145  * (black) is harmless — the guard means the value is never used. */
1146  double bg_r = 0.0, bg_g = 0.0, bg_b = 0.0; /* Background color */
1147 
1148 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
1149  // Fix for cairo 1.17.6 and above which sets to surface unit back to PT (default: UNIT_USER)
1150 
1151  cairo_surface_t* cSurface = cairo_get_target(cairoTarget);
1152  if (cairo_surface_get_type(cSurface) == CAIRO_SURFACE_TYPE_SVG) {
1153  cairo_svg_surface_set_document_unit(cSurface, CAIRO_SVG_UNIT_PT);
1154  }
1155 #endif
1156 
1157  doVectorExportFix =
1158  draw_do_vector_export_fix (cairoTarget, &bg_r, &bg_g, &bg_b);
1159 
1160  /* If we are scaling the image at all, ignore the line width checks
1161  * since scaled up lines can still be visible */
1162  if ((scaleX != 1)||(scaleY != 1)){
1163  limitLineWidth = FALSE;
1164  }
1165 
1166  if (transform.mirrorAroundX) {
1167  scaleY *= -1;
1168  pnp_label_scale_y = 1;
1169  }
1170 
1171  if (transform.mirrorAroundY) {
1172  scaleX *= -1;
1173  pnp_label_scale_x= -1;
1174  }
1175 
1176  cairo_translate (cairoTarget, transform.translateX, transform.translateY);
1177  cairo_scale (cairoTarget, scaleX, scaleY);
1178  cairo_rotate (cairoTarget, transform.rotation);
1179 
1180  gboolean useOptimizations = allowOptimization;
1181 
1182  /* If the user is using any transformations for this layer, then don't
1183  * bother using rendering optimizations */
1184  if (fabs(transform.translateX) > GERBV_PRECISION_LINEAR_INCH
1185  || fabs(transform.translateY) > GERBV_PRECISION_LINEAR_INCH
1186  || fabs(transform.scaleX - 1) > GERBV_PRECISION_LINEAR_INCH
1187  || fabs(transform.scaleY - 1) > GERBV_PRECISION_LINEAR_INCH
1188  || fabs(transform.rotation) > GERBV_PRECISION_ANGLE_RAD
1189  || transform.mirrorAroundX || transform.mirrorAroundY)
1190  useOptimizations = FALSE;
1191 
1192  if (useOptimizations && pixelOutput) {
1193  minX = renderInfo->lowerLeftX;
1194  minY = renderInfo->lowerLeftY;
1195  maxX = renderInfo->lowerLeftX + (renderInfo->displayWidth /
1196  renderInfo->scaleFactorX);
1197  maxY = renderInfo->lowerLeftY + (renderInfo->displayHeight /
1198  renderInfo->scaleFactorY);
1199  }
1200 
1201  /* do initial justify */
1202  cairo_translate (cairoTarget, image->info->imageJustifyOffsetActualA,
1203  image->info->imageJustifyOffsetActualB);
1204 
1205  /* set the fill rule so aperture holes are cleared correctly */
1206  cairo_set_fill_rule (cairoTarget, CAIRO_FILL_RULE_EVEN_ODD);
1207  /* offset image */
1208  cairo_translate (cairoTarget, image->info->offsetA, image->info->offsetB);
1209  /* do image rotation */
1210  cairo_rotate (cairoTarget, image->info->imageRotation);
1211 
1212  /* load in polarity operators depending on the image polarity */
1213  invertPolarity = transform.inverted;
1214  if (image->info->polarity == GERBV_POLARITY_NEGATIVE)
1215  invertPolarity = !invertPolarity;
1216  if (drawMode == DRAW_SELECTIONS)
1217  invertPolarity = FALSE;
1218 
1219  if (invertPolarity) {
1220  drawOperatorClear = CAIRO_OPERATOR_OVER;
1221  drawOperatorDark = CAIRO_OPERATOR_CLEAR;
1222  cairo_set_operator (cairoTarget, CAIRO_OPERATOR_OVER);
1223  cairo_paint (cairoTarget);
1224  cairo_set_operator (cairoTarget, CAIRO_OPERATOR_CLEAR);
1225  } else {
1226  drawOperatorClear = CAIRO_OPERATOR_CLEAR;
1227  drawOperatorDark = CAIRO_OPERATOR_OVER;
1228  }
1229 
1230  /* next, push two cairo states to simulate the first layer and netstate
1231  translations (these will be popped when another layer or netstate is
1232  started */
1233  cairo_save (cairoTarget);
1234  cairo_save (cairoTarget);
1235 
1236  /* store the current layer and netstate so we know when they change */
1237  oldLayer = image->layers;
1238  oldState = image->states;
1239 
1240  const char *pnp_net_label_str_prev = NULL;
1241 
1242  for (net = image->netlist->next; net != NULL;
1244 
1245  /* check if this is a new layer */
1246  if (net->layer != oldLayer){
1247  /* it's a new layer, so recalculate the new transformation matrix
1248  for it */
1249  cairo_restore (cairoTarget);
1250  cairo_restore (cairoTarget);
1251  cairo_save (cairoTarget);
1252  /* do any rotations */
1253  cairo_rotate (cairoTarget, net->layer->rotation);
1254  /* handle the layer polarity */
1255  if ((net->layer->polarity == GERBV_POLARITY_CLEAR)^invertPolarity) {
1256  cairo_set_operator (cairoTarget, CAIRO_OPERATOR_CLEAR);
1257  drawOperatorClear = CAIRO_OPERATOR_OVER;
1258  drawOperatorDark = CAIRO_OPERATOR_CLEAR;
1259  }
1260  else {
1261  cairo_set_operator (cairoTarget, CAIRO_OPERATOR_OVER);
1262  drawOperatorClear = CAIRO_OPERATOR_CLEAR;
1263  drawOperatorDark = CAIRO_OPERATOR_OVER;
1264  }
1265 
1266  /* Draw any knockout areas */
1267  gerbv_knockout_t *ko = &net->layer->knockout;
1268  if (ko->firstInstance == TRUE) {
1269  cairo_save (cairoTarget);
1270 
1271  if (ko->polarity == GERBV_POLARITY_CLEAR) {
1272  cairo_set_operator (cairoTarget, drawOperatorClear);
1273  } else {
1274  cairo_set_operator (cairoTarget, drawOperatorDark);
1275  }
1276 
1277  if (doVectorExportFix
1278  && CAIRO_OPERATOR_CLEAR ==
1279  cairo_get_operator (cairoTarget)) {
1280 
1281  cairo_set_operator (cairoTarget,
1282  CAIRO_OPERATOR_OVER);
1283  cairo_set_source_rgba (
1284  cairoTarget, bg_r,
1285  bg_g, bg_b, 1.0);
1286  }
1287 
1288  cairo_new_path (cairoTarget);
1289  cairo_rectangle (cairoTarget,
1290  ko->lowerLeftX - ko->border,
1291  ko->lowerLeftY - ko->border,
1292  ko->width + 2*ko->border,
1293  ko->height + 2*ko->border);
1294  draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
1295 
1296  cairo_restore (cairoTarget);
1297  }
1298 
1299  /* Finally, reapply old netstate transformation */
1300  cairo_save (cairoTarget);
1301  draw_apply_netstate_transformation (cairoTarget, net->state);
1302  oldLayer = net->layer;
1303  }
1304 
1305  /* check if this is a new netstate */
1306  if (net->state != oldState){
1307  /* pop the transformation matrix back to the "pre-state" state and
1308  resave it */
1309  cairo_restore (cairoTarget);
1310  cairo_save (cairoTarget);
1311  /* it's a new state, so recalculate the new transformation matrix
1312  for it */
1313  draw_apply_netstate_transformation (cairoTarget, net->state);
1314  oldState = net->state;
1315  }
1316 
1317  /* if we are only drawing from the selection buffer, search if this net is
1318  in the buffer */
1319  if (drawMode == DRAW_SELECTIONS) {
1320  /* this flag makes sure we don't draw any unintentional polygons...
1321  if we've successfully entered a polygon (the first net matches, and
1322  we don't want to check the nets inside the polygon) then
1323  polygonStartNet will be set */
1324  if (!polygonStartNet) {
1326  selectionInfo, FALSE))
1327  continue;
1328  }
1329  }
1330 
1331  /* Render any labels attached to this net */
1332  /* NOTE: this is currently only used on PNP files, so we may
1333  make some assumptions here... */
1334  if (drawMode != DRAW_SELECTIONS && net->label
1337  && g_strcmp0 (net->label->str, pnp_net_label_str_prev)) {
1338 
1339  double mark_x, mark_y;
1340 
1341  /* Add PNP text label only one time per
1342  * net and if it is not selected. */
1343  pnp_net_label_str_prev =
1344  net->label->str;
1345 
1346  if (draw_calc_pnp_mark_coords(net, &mark_x, &mark_y)) {
1347  cairo_save (cairoTarget);
1348 
1349  cairo_set_font_size (cairoTarget, 0.05);
1350  cairo_move_to (cairoTarget, mark_x, mark_y);
1351  cairo_scale (cairoTarget, pnp_label_scale_x,
1352  pnp_label_scale_y);
1353  cairo_show_text (cairoTarget, net->label->str);
1354 
1355  cairo_restore (cairoTarget);
1356  }
1357  }
1358 
1359  /* step and repeat */
1360  gerbv_step_and_repeat_t *sr = &net->layer->stepAndRepeat;
1361  int ix, iy;
1362  for (ix = 0; ix < sr->X; ix++) {
1363  for (iy = 0; iy < sr->Y; iy++) {
1364  double sr_x = ix * sr->dist_X;
1365  double sr_y = iy * sr->dist_Y;
1366 
1367  if (useOptimizations && pixelOutput
1368  && ((net->boundingBox.right+sr_x < minX)
1369  || (net->boundingBox.left+sr_x > maxX)
1370  || (net->boundingBox.top+sr_y < minY)
1371  || (net->boundingBox.bottom+sr_y > maxY))) {
1372  continue;
1373  }
1374 
1375  x1 = net->start_x + sr_x;
1376  y1 = net->start_y + sr_y;
1377  x2 = net->stop_x + sr_x;
1378  y2 = net->stop_y + sr_y;
1379 
1380  /* translate circular x,y data as well */
1381  if (net->cirseg) {
1382  cp_x = net->cirseg->cp_x + sr_x;
1383  cp_y = net->cirseg->cp_y + sr_y;
1384  }
1385 
1386  /* Polygon area fill routines */
1387  switch (net->interpolation) {
1389 
1390  if (doVectorExportFix
1391  && CAIRO_OPERATOR_CLEAR ==
1392  cairo_get_operator (cairoTarget)) {
1393 
1394  cairo_save (cairoTarget);
1395 
1396  cairo_set_operator (cairoTarget,
1397  CAIRO_OPERATOR_OVER);
1398  cairo_set_source_rgba (
1399  cairoTarget, bg_r,
1400  bg_g, bg_b, 1.0);
1401 
1402  draw_render_polygon_object (net,
1403  cairoTarget,
1404  sr_x, sr_y, image,
1405  drawMode, selectionInfo,
1406  pixelOutput);
1407 
1408  cairo_restore (cairoTarget);
1409  } else {
1410  draw_render_polygon_object (net,
1411  cairoTarget,
1412  sr_x, sr_y, image,
1413  drawMode, selectionInfo,
1414  pixelOutput);
1415  }
1416 
1417  continue;
1419  continue;
1420  default :
1421  break;
1422  }
1423 
1424  /*
1425  * If aperture state is off we allow use of undefined apertures.
1426  * This happens when gerber files starts, but hasn't decided on
1427  * which aperture to use.
1428  */
1429  if (image->aperture[net->aperture] == NULL)
1430  continue;
1431 
1432  switch (net->aperture_state) {
1434  /* if the aperture width is truly 0, then render as a 1 pixel width
1435  line. 0 diameter apertures are used by some programs to draw labels,
1436  etc, and they are rendered by other programs as 1 pixel wide */
1437  /* NOTE: also, make sure all lines are at least 1 pixel wide, so they
1438  always show up at low zoom levels */
1439 
1440  if (limitLineWidth&&((image->aperture[net->aperture]->parameter[0] < pixelWidth)&&
1441  (pixelOutput)))
1442  criticalRadius = pixelWidth/2.0;
1443  else
1444  criticalRadius = image->aperture[net->aperture]->parameter[0]/2.0;
1445  lineWidth = criticalRadius*2.0;
1446  // convert to a pixel integer
1447  cairo_user_to_device_distance (cairoTarget, &lineWidth, &x1);
1448  if (pixelOutput) {
1449  lineWidth = round(lineWidth);
1450  if ((int)lineWidth % 2) {
1451  oddWidth = TRUE;
1452  }
1453  else {
1454  oddWidth = FALSE;
1455  }
1456  }
1457  cairo_device_to_user_distance (cairoTarget, &lineWidth, &x1);
1458  cairo_set_line_width (cairoTarget, lineWidth);
1459 
1460  switch (net->interpolation) {
1465  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1466 
1467  /* weed out any lines that are
1468  * obviously not going to
1469  * render on the visible screen */
1470  switch (image->aperture[net->aperture]->type) {
1471  case GERBV_APTYPE_CIRCLE :
1472  if (renderInfo->show_cross_on_drill_holes
1473  && image->layertype == GERBV_LAYERTYPE_DRILL) {
1474  /* Draw center crosses on slot hole */
1475  cairo_set_line_width (cairoTarget, pixelWidth);
1476  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE);
1477  r = image->aperture[net->aperture]->parameter[0]/2.0 +
1478  hole_cross_inc_px*pixelWidth;
1479  draw_cairo_cross (cairoTarget, x1, y1, r);
1480  draw_cairo_cross (cairoTarget, x2, y2, r);
1481  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1482  cairo_set_line_width (cairoTarget, lineWidth);
1483  }
1484 
1485  draw_cairo_move_to (cairoTarget, x1, y1, oddWidth, pixelOutput);
1486  draw_cairo_line_to (cairoTarget, x2, y2, oddWidth, pixelOutput);
1487 
1488  if (doVectorExportFix
1489  && CAIRO_OPERATOR_CLEAR ==
1490  cairo_get_operator (cairoTarget)) {
1491  cairo_save (cairoTarget);
1492  cairo_set_source_rgba (
1493  cairoTarget,
1494  bg_r,
1495  bg_g,
1496  bg_b,
1497  1.0);
1498  cairo_set_operator (
1499  cairoTarget,
1500  CAIRO_OPERATOR_OVER);
1501 
1502  draw_stroke (
1503  cairoTarget,
1504  drawMode,
1505  selectionInfo,
1506  image, net);
1507 
1508  cairo_restore (
1509  cairoTarget);
1510  } else {
1511  draw_stroke (
1512  cairoTarget,
1513  drawMode,
1514  selectionInfo,
1515  image, net);
1516  }
1517 
1518  break;
1519  case GERBV_APTYPE_RECTANGLE :
1520  dx = image->aperture[net->aperture]->parameter[0]/2;
1521  dy = image->aperture[net->aperture]->parameter[1]/2;
1522  if(x1 > x2)
1523  dx = -dx;
1524  if(y1 > y2)
1525  dy = -dy;
1526  cairo_new_path(cairoTarget);
1527  draw_cairo_move_to (cairoTarget, x1 - dx, y1 - dy, FALSE, pixelOutput);
1528  draw_cairo_line_to (cairoTarget, x1 - dx, y1 + dy, FALSE, pixelOutput);
1529  draw_cairo_line_to (cairoTarget, x2 - dx, y2 + dy, FALSE, pixelOutput);
1530  draw_cairo_line_to (cairoTarget, x2 + dx, y2 + dy, FALSE, pixelOutput);
1531  draw_cairo_line_to (cairoTarget, x2 + dx, y2 - dy, FALSE, pixelOutput);
1532  draw_cairo_line_to (cairoTarget, x1 + dx, y1 - dy, FALSE, pixelOutput);
1533  draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
1534  break;
1535  /* TODO: for now, just render ovals or polygons like a circle */
1536  case GERBV_APTYPE_OVAL :
1537  case GERBV_APTYPE_POLYGON :
1538  draw_cairo_move_to (cairoTarget, x1,y1, oddWidth, pixelOutput);
1539  draw_cairo_line_to (cairoTarget, x2,y2, oddWidth, pixelOutput);
1540  draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
1541  break;
1542  /* macros can only be flashed, so ignore any that might be here */
1543  default:
1544  GERB_COMPILE_WARNING(
1545  _("Unknown aperture type: %s"),
1547  image->aperture[net->aperture]->type)));
1548  break;
1549  }
1550  break;
1553  /* cairo doesn't have a function to draw oval arcs, so we must
1554  * draw an arc and stretch it by scaling different x and y values
1555  */
1556  cairo_new_path(cairoTarget);
1557  if (image->aperture[net->aperture]->type == GERBV_APTYPE_RECTANGLE) {
1558  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE);
1559  }
1560  else {
1561  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1562  }
1563  cairo_save (cairoTarget);
1564  cairo_translate(cairoTarget, cp_x, cp_y);
1565  cairo_scale (cairoTarget, net->cirseg->width, net->cirseg->height);
1566  if (net->cirseg->angle2 > net->cirseg->angle1) {
1567  cairo_arc (cairoTarget, 0.0, 0.0, 0.5,
1568  DEG2RAD(net->cirseg->angle1),
1569  DEG2RAD(net->cirseg->angle2));
1570  }
1571  else {
1572  cairo_arc_negative (cairoTarget, 0.0, 0.0, 0.5,
1573  DEG2RAD(net->cirseg->angle1),
1574  DEG2RAD(net->cirseg->angle2));
1575  }
1576  cairo_restore (cairoTarget);
1577  draw_stroke (cairoTarget, drawMode, selectionInfo, image, net);
1578  break;
1579  default :
1580  GERB_COMPILE_WARNING(
1581  _("Unknown interpolation type: %s"),
1583  break;
1584  }
1585  break;
1587  break;
1589  p = image->aperture[net->aperture]->parameter;
1590 
1591  cairo_save (cairoTarget);
1592  draw_cairo_translate_adjust(cairoTarget, x2, y2, pixelOutput);
1593 
1594  /* Set TRUE when the aperture type has already painted
1595  * its own pixels (macros via gerbv_draw_amacro, blocks
1596  * via draw_render_block_nets). Skips the trailing
1597  * draw_fill on the empty current path — harmless under
1598  * Cairo but semantically incorrect (and a stale call
1599  * that future readers would have to chase). */
1600  gboolean skip_shared_fill = FALSE;
1601 
1602  switch (image->aperture[net->aperture]->type) {
1603  case GERBV_APTYPE_CIRCLE :
1604  if (renderInfo->show_cross_on_drill_holes
1605  && image->layertype == GERBV_LAYERTYPE_DRILL) {
1606  /* Draw center cross on drill hole */
1607  cairo_set_line_width (cairoTarget, pixelWidth);
1608  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_SQUARE);
1609  r = p[0]/2.0 + hole_cross_inc_px*pixelWidth;
1610  draw_cairo_cross (cairoTarget, 0, 0, r);
1611  cairo_set_line_width (cairoTarget, lineWidth);
1612  cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
1613  }
1614 
1615  gerbv_draw_circle(cairoTarget, p[0]);
1616  gerbv_draw_aperture_hole (cairoTarget, p[1], p[2], pixelOutput);
1617  break;
1618  case GERBV_APTYPE_RECTANGLE :
1619  // some CAD programs use very thin flashed rectangles to compose
1620  // logos/images, so we must make sure those display here
1621  displayPixel = pixelOutput;
1622  p0 = p[0];
1623  p1 = p[1];
1624  if (limitLineWidth && (p[0] < pixelWidth) && pixelOutput) {
1625  p0 = pixelWidth;
1626  displayPixel = FALSE;
1627  }
1628  if (limitLineWidth && (p[1] < pixelWidth) && pixelOutput) {
1629  p1 = pixelWidth;
1630  displayPixel = FALSE;
1631  }
1632  gerbv_draw_rectangle(cairoTarget, p0, p1, displayPixel);
1633  gerbv_draw_aperture_hole (cairoTarget, p[2], p[3], displayPixel);
1634  break;
1635  case GERBV_APTYPE_OVAL :
1636  gerbv_draw_oblong(cairoTarget, p[0], p[1]);
1637  gerbv_draw_aperture_hole (cairoTarget, p[2], p[3], pixelOutput);
1638  break;
1639  case GERBV_APTYPE_POLYGON :
1640  gerbv_draw_polygon(cairoTarget, p[0], p[1], p[2]);
1641  gerbv_draw_aperture_hole (cairoTarget, p[3], p[4], pixelOutput);
1642  break;
1643  case GERBV_APTYPE_MACRO :
1644 /* TODO: to do it properly for vector export (doVectorExportFix) draw all
1645  * macros with some vector library with logical operators */
1646  gerbv_draw_amacro(cairoTarget, drawOperatorClear, drawOperatorDark,
1647  image->aperture[net->aperture]->simplified,
1648  (gint)p[0], pixelWidth,
1649  drawMode, selectionInfo, image, net);
1650  skip_shared_fill = TRUE;
1651  break;
1652  case GERBV_APTYPE_BLOCK :
1653  draw_render_block_nets (cairoTarget, image,
1654  image->aperture[net->aperture]->block_netlist,
1655  net, drawMode, selectionInfo,
1656  pixelOutput, pixelWidth, lineWidth,
1657  drawOperatorClear, drawOperatorDark);
1658  skip_shared_fill = TRUE;
1659  break;
1660  default :
1661  GERB_COMPILE_WARNING(
1662  _("Unknown aperture type: %s"),
1664  image->aperture[net->aperture]->type)));
1665  return 0;
1666  }
1667 
1668  /* And finally fill the path */
1669  if (doVectorExportFix
1670  && CAIRO_OPERATOR_CLEAR ==
1671  cairo_get_operator (cairoTarget)) {
1672  cairo_set_source_rgba (
1673  cairoTarget,
1674  bg_r, bg_g,
1675  bg_b, 1.0);
1676  cairo_set_operator (cairoTarget,
1677  CAIRO_OPERATOR_OVER);
1678  }
1679 
1680  if (!skip_shared_fill)
1681  draw_fill (cairoTarget, drawMode, selectionInfo, image, net);
1682  cairo_restore (cairoTarget);
1683  break;
1684  default:
1685  GERB_COMPILE_WARNING(
1686  _("Unknown aperture state: %s"),
1688  net->aperture_state)));
1689 
1690  return 0;
1691  }
1692  }
1693  }
1694  }
1695 
1696  /* restore the initial two state saves (one for layer, one for netstate)*/
1697  cairo_restore (cairoTarget);
1698  cairo_restore (cairoTarget);
1699 
1700  return 1;
1701 }
1702 
1703 /* Check if Cairo target require the vector export fix to be done and if so try
1704  * to retrieve background color. */
1705 static gboolean
1706 draw_do_vector_export_fix(cairo_t *cairoTarget,
1707  double *bg_red, double *bg_green, double *bg_blue)
1708 {
1709  /* Cairo library produce _raster_ output if polygon is cleared by
1710  * negative aperture or other polygon. A workaround is to draw over
1711  * with background color instead of clearing. Drawback is: there won't
1712  * be any see thru negative opening if two layers printed one on the
1713  * another. */
1714 
1715  switch (cairo_surface_get_type (cairo_get_target (cairoTarget))) {
1716 
1717  case CAIRO_SURFACE_TYPE_PDF:
1718  case CAIRO_SURFACE_TYPE_PS:
1719  case CAIRO_SURFACE_TYPE_SVG: {
1720  double *p0, *p1, *p2;
1721 
1722  /* Get background color from cairo user data to emulate clear
1723  * operator */
1724  p0 = cairo_get_user_data (cairoTarget,
1725  (cairo_user_data_key_t *)0);
1726  p1 = cairo_get_user_data (cairoTarget,
1727  (cairo_user_data_key_t *)1);
1728  p2 = cairo_get_user_data (cairoTarget,
1729  (cairo_user_data_key_t *)2);
1730 
1731  if (p0 != NULL && p1 != NULL && p2 != NULL) {
1732  *bg_red = *p0;
1733  *bg_green = *p1;
1734  *bg_blue = *p2;
1735  } else {
1736  *bg_red = *bg_green = *bg_blue = 1.0;
1737  }
1738 
1739  break;
1740  }
1741 
1742  default:
1743  return FALSE;
1744  }
1745 
1746  return TRUE;
1747 }
void draw_cairo_translate_adjust(cairo_t *cairoTarget, gdouble x, gdouble y, gboolean pixelOutput)
Cairo translate user-space origin.
Definition: draw.c:100
static gboolean draw_net_is_in_selection_buffer_remove(gerbv_net_t *net, gerbv_selection_info_t *selectionInfo, gboolean remove)
Check if net is in selection buffer and possibly deselect it.
Definition: draw.c:120
static void draw_render_block_nets(cairo_t *cairoTarget, gerbv_image_t *image, gerbv_net_t *block_netlist, gerbv_net_t *flash_net, enum draw_mode drawMode, gerbv_selection_info_t *selectionInfo, gboolean pixelOutput, gdouble pixelWidth, gdouble lineWidth, cairo_operator_t drawOperatorClear, cairo_operator_t drawOperatorDark)
Render all nets within a block aperture's net list.
Definition: draw.c:950
static void draw_cairo_cross(cairo_t *cairoTarget, gdouble xc, gdouble yc, gdouble r)
Draw Cairo cross.
Definition: draw.c:881
static void gerbv_draw_rectangle(cairo_t *cairoTarget, gdouble width, gdouble height, gboolean pixelOutput)
Draw the rectangle centered at current Cairo coordinates.
Definition: draw.c:244
void draw_cairo_line_to(cairo_t *cairoTarget, gdouble x, gdouble y, gboolean adjustByHalf, gboolean pixelOutput)
Draw Cairo line from current coordinates.
Definition: draw.c:55
void draw_cairo_move_to(cairo_t *cairoTarget, gdouble x, gdouble y, gboolean oddWidth, gboolean pixelOutput)
Move Cairo coordinates.
Definition: draw.c:78
static void gerbv_draw_oblong(cairo_t *cairoTarget, gdouble width, gdouble height)
Draw the oblong centered at current Cairo coordinates.
Definition: draw.c:264
static void gerbv_draw_circle(cairo_t *cairoTarget, gdouble diameter)
Draw the circle centered at current Cairo coordinates.
Definition: draw.c:231
Header info for the cairo rendering functions and the related selection calculating functions.
gerbv_net_t * gerbv_image_return_next_renderable_object(gerbv_net_t *oldNet)
Return the next net entry which corresponds to a unique visible object.
Definition: gerb_image.c:1387
const char * gerbv_interpolation_name(gerbv_interpolation_t interp)
Return string name of gerbv_interpolation_t interpolation.
Definition: gerbv.c:116
const char * gerbv_aperture_state_name(gerbv_aperture_state_t state)
Definition: gerbv.c:100
const char * gerbv_aperture_type_name(gerbv_aperture_type_t type)
Return string name of gerbv_aperture_type_t aperture type.
Definition: gerbv.c:72
The main header file for the libgerbv library.
@ GERBV_APERTURE_STATE_OFF
Definition: gerbv.h:179
@ GERBV_APERTURE_STATE_ON
Definition: gerbv.h:180
@ GERBV_APERTURE_STATE_FLASH
Definition: gerbv.h:181
@ GERBV_POLARITY_CLEAR
Definition: gerbv.h:285
@ GERBV_POLARITY_NEGATIVE
Definition: gerbv.h:283
@ GERBV_SELECTION_POINT_CLICK
Definition: gerbv.h:356
@ GERBV_SELECTION_DRAG_BOX
Definition: gerbv.h:357
@ GERBV_APTYPE_MACRO_LINE20
Definition: gerbv.h:170
@ GERBV_APTYPE_MACRO_LINE21
Definition: gerbv.h:171
@ GERBV_APTYPE_OVAL
Definition: gerbv.h:162
@ GERBV_APTYPE_MACRO_OUTLINE
Definition: gerbv.h:166
@ GERBV_APTYPE_MACRO_CIRCLE
Definition: gerbv.h:165
@ GERBV_APTYPE_MACRO
Definition: gerbv.h:164
@ GERBV_APTYPE_CIRCLE
Definition: gerbv.h:160
@ GERBV_APTYPE_POLYGON
Definition: gerbv.h:163
@ GERBV_APTYPE_MACRO_POLYGON
Definition: gerbv.h:167
@ GERBV_APTYPE_RECTANGLE
Definition: gerbv.h:161
@ GERBV_APTYPE_MACRO_THERMAL
Definition: gerbv.h:169
@ GERBV_APTYPE_MACRO_LINE22
Definition: gerbv.h:172
@ GERBV_APTYPE_MACRO_MOIRE
Definition: gerbv.h:168
@ GERBV_APTYPE_BLOCK
Definition: gerbv.h:173
@ GERBV_INTERPOLATION_LINEARx01
Definition: gerbv.h:305
@ GERBV_INTERPOLATION_PAREA_START
Definition: gerbv.h:309
@ GERBV_INTERPOLATION_LINEARx001
Definition: gerbv.h:306
@ GERBV_INTERPOLATION_DELETED
Definition: gerbv.h:311
@ GERBV_INTERPOLATION_CW_CIRCULAR
Definition: gerbv.h:307
@ GERBV_INTERPOLATION_PAREA_END
Definition: gerbv.h:310
@ GERBV_INTERPOLATION_LINEARx10
Definition: gerbv.h:304
@ GERBV_INTERPOLATION_CCW_CIRCULAR
Definition: gerbv.h:308
@ GERBV_INTERPOLATION_LINEARx1
Definition: gerbv.h:303
@ GERBV_LAYERTYPE_PICKANDPLACE_BOT
Definition: gerbv.h:332
@ GERBV_LAYERTYPE_PICKANDPLACE_TOP
Definition: gerbv.h:331
@ GERBV_LAYERTYPE_DRILL
Definition: gerbv.h:330
Header info for the selection support functions for libgerbv.
gerbv_layer_t * layers
Definition: gerbv.h:736
gerbv_layertype_t layertype
Definition: gerbv.h:734
gerbv_net_t * netlist
Definition: gerbv.h:741
gerbv_aperture_t * aperture[APERTURE_MAX]
Definition: gerbv.h:735
gerbv_netstate_t * states
Definition: gerbv.h:737
gerbv_image_info_t * info
Definition: gerbv.h:740
gerbv_step_and_repeat_t stepAndRepeat
Definition: gerbv.h:646
gerbv_polarity_t polarity
Definition: gerbv.h:649
gerbv_knockout_t knockout
Definition: gerbv.h:647
gdouble rotation
Definition: gerbv.h:648
gerbv_render_size_t boundingBox
Definition: gerbv.h:673
gerbv_layer_t * layer
Definition: gerbv.h:680
double stop_y
Definition: gerbv.h:672
GString * label
Definition: gerbv.h:679
gerbv_aperture_state_t aperture_state
Definition: gerbv.h:675
double stop_x
Definition: gerbv.h:671
double start_x
Definition: gerbv.h:669
gerbv_netstate_t * state
Definition: gerbv.h:681
struct gerbv_net * next
Definition: gerbv.h:678
double start_y
Definition: gerbv.h:670
gerbv_interpolation_t interpolation
Definition: gerbv.h:676
gerbv_cirseg_t * cirseg
Definition: gerbv.h:677
int aperture
Definition: gerbv.h:674
gdouble offsetB
Definition: gerbv.h:660
gdouble scaleA
Definition: gerbv.h:661
gdouble scaleB
Definition: gerbv.h:662
gerbv_axis_select_t axisSelect
Definition: gerbv.h:656
gdouble rotation
Definition: gerbv.h:663
gdouble offsetA
Definition: gerbv.h:659
gerbv_mirror_state_t mirrorState
Definition: gerbv.h:657
gdouble lowerLeftY
Definition: gerbv.h:790
gboolean show_cross_on_drill_holes
Definition: gerbv.h:794
gdouble scaleFactorX
Definition: gerbv.h:787
gint displayHeight
Definition: gerbv.h:793
gdouble lowerLeftX
Definition: gerbv.h:789
gdouble scaleFactorY
Definition: gerbv.h:788