2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
30 #include <math.h> /* ceil(), atan2() */
42 #define dprintf if(DEBUG) printf
44 draw_check_if_object_is_in_selected_area (cairo_t
*cairoTarget
, gboolean isStroke
,
45 gerbv_selection_info_t
*selectionInfo
, gerbv_image_t
*image
, struct gerbv_net
*net
){
46 gdouble corner1X
,corner1Y
,corner2X
,corner2Y
;
48 corner1X
= selectionInfo
->lowerLeftX
;
49 corner1Y
= selectionInfo
->lowerLeftY
;
50 corner2X
= selectionInfo
->upperRightX
;
51 corner2Y
= selectionInfo
->upperRightY
;
53 /* calculate the coordinate of the user's click in the current
54 transformation matrix */
55 cairo_device_to_user (cairoTarget
, &corner1X
, &corner1Y
);
56 cairo_device_to_user (cairoTarget
, &corner2X
, &corner2Y
);
57 if (selectionInfo
->type
== POINT_CLICK
) {
58 /* use the cairo in_fill routine to see if the point is within the
60 if ((isStroke
&& cairo_in_stroke (cairoTarget
, corner1X
, corner1Y
)) ||
61 (!isStroke
&& cairo_in_fill (cairoTarget
, corner1X
, corner1Y
))) {
62 /* add the net to the selection array */
63 gerbv_selection_item_t sItem
= {image
, net
};
64 g_array_append_val (selectionInfo
->selectedNodeArray
, sItem
);
67 else if (selectionInfo
->type
== DRAG_BOX
) {
69 gdouble minX
,minY
,maxX
,maxY
;
71 /* we can't assume the "lowerleft" corner is actually in the lower left,
72 since the cairo transformation matrix may be mirrored,etc */
73 minX
= MIN(corner1X
,corner2X
);
74 maxX
= MAX(corner1X
,corner2X
);
75 minY
= MIN(corner1Y
,corner2Y
);
76 maxY
= MAX(corner1Y
,corner2Y
);
78 cairo_stroke_extents (cairoTarget
, &x1
, &y1
, &x2
, &y2
);
80 cairo_fill_extents (cairoTarget
, &x1
, &y1
, &x2
, &y2
);
82 if ((minX
< x1
) && (minY
< y1
) && (maxX
> x2
) && (maxY
> y2
)) {
83 /* add the net to the selection array */
84 gerbv_selection_item_t sItem
= {image
, net
};
85 g_array_append_val (selectionInfo
->selectedNodeArray
, sItem
);
88 /* clear the path, since we didn't actually draw it and cairo
89 doesn't reset it after the previous calls */
90 cairo_new_path (cairoTarget
);
94 draw_fill (cairo_t
*cairoTarget
, gchar drawMode
, gerbv_selection_info_t
*selectionInfo
,
95 gerbv_image_t
*image
, struct gerbv_net
*net
){
96 if ((drawMode
== DRAW_IMAGE
) || (drawMode
== DRAW_SELECTIONS
))
97 cairo_fill (cairoTarget
);
99 draw_check_if_object_is_in_selected_area (cairoTarget
, FALSE
,
100 selectionInfo
, image
, net
);
104 draw_stroke (cairo_t
*cairoTarget
, gchar drawMode
, gerbv_selection_info_t
*selectionInfo
,
105 gerbv_image_t
*image
, struct gerbv_net
*net
){
106 if ((drawMode
== DRAW_IMAGE
) || (drawMode
== DRAW_SELECTIONS
))
107 cairo_stroke (cairoTarget
);
109 draw_check_if_object_is_in_selected_area (cairoTarget
, TRUE
,
110 selectionInfo
, image
, net
);
114 * Draws a circle _centered_ at x,y with diameter dia
117 gerbv_draw_circle(cairo_t
*cairoTarget
, gdouble diameter
)
119 cairo_arc (cairoTarget
, 0.0, 0.0, diameter
/2.0, 0, 2.0*M_PI
);
121 } /* gerbv_draw_circle */
125 * Draws a rectangle _centered_ at x,y with sides x_side, y_side
128 gerbv_draw_rectangle(cairo_t
*cairoTarget
, gdouble width
, gdouble height
)
130 cairo_rectangle (cairoTarget
, - width
/ 2.0, - height
/ 2.0, width
, height
);
132 } /* gerbv_draw_rectangle */
136 * Draws an oblong _centered_ at x,y with x axis x_axis and y axis y_axis
139 gerbv_draw_oblong(cairo_t
*cairoTarget
, gdouble width
, gdouble height
)
142 cairo_new_path (cairoTarget);
143 cairo_set_line_cap (cairoTarget, CAIRO_LINE_CAP_ROUND);
144 cairo_set_line_width (cairoTarget, height);
145 cairo_move_to (cairoTarget, -width/2.0 + height/2.0, 0);
146 cairo_line_to (cairoTarget, width/2.0 - height/2.0, 0);
147 draw_stroke (cairoTarget, drawMode, selectionInfo);
149 /* cairo doesn't have a function to draw ovals, so we must
150 * draw an arc and stretch it by scaling different x and y values
152 cairo_save (cairoTarget
);
153 cairo_scale (cairoTarget
, width
, height
);
154 gerbv_draw_circle (cairoTarget
, 1);
155 cairo_restore (cairoTarget
);
157 } /* gerbv_draw_oval */
161 gerbv_draw_polygon(cairo_t
*cairoTarget
, gdouble outsideDiameter
,
162 gdouble numberOfSides
, gdouble degreesOfRotation
)
164 int i
, numberOfSidesInteger
= (int) numberOfSides
;
166 cairo_rotate(cairoTarget
, degreesOfRotation
* M_PI
/180);
167 cairo_move_to(cairoTarget
, outsideDiameter
/ 2.0, 0);
168 /* skip first point, since we've moved there already */
169 /* include last point, since we may be drawing an aperture hole next
170 and cairo may not correctly close the path itself */
171 for (i
= 1; i
<= (int)numberOfSidesInteger
; i
++){
172 gdouble angle
= (double) i
/ numberOfSidesInteger
* M_PI
* 2.0;
173 cairo_line_to (cairoTarget
, cos(angle
) * outsideDiameter
/ 2.0,
174 sin(angle
) * outsideDiameter
/ 2.0);
177 } /* gerbv_draw_polygon */
181 gerbv_draw_aperature_hole(cairo_t
*cairoTarget
, gdouble dimensionX
, gdouble dimensionY
)
185 gerbv_draw_rectangle (cairoTarget
, dimensionX
, dimensionY
);
187 gerbv_draw_circle (cairoTarget
, dimensionX
);
191 } /* gerbv_draw_aperature_hole */
194 draw_update_macro_exposure (cairo_t
*cairoTarget
, cairo_operator_t clearOperator
,
195 cairo_operator_t darkOperator
, gdouble exposureSetting
){
197 if (exposureSetting
== 0.0) {
198 cairo_set_operator (cairoTarget
, clearOperator
);
200 else if (exposureSetting
== 1.0) {
201 cairo_set_operator (cairoTarget
, darkOperator
);
203 else if (exposureSetting
== 2.0) {
204 /* reverse current exposure setting */
205 cairo_operator_t currentOperator
= cairo_get_operator (cairoTarget
);
206 if (currentOperator
== clearOperator
) {
207 cairo_set_operator (cairoTarget
, darkOperator
);
210 cairo_set_operator (cairoTarget
, clearOperator
);
218 gerbv_draw_amacro(cairo_t
*cairoTarget
, cairo_operator_t clearOperator
,
219 cairo_operator_t darkOperator
, gerbv_simplified_amacro_t
*s
,
220 gint usesClearPrimative
, gchar drawMode
, gerbv_selection_info_t
*selectionInfo
,
221 gerbv_image_t
*image
, struct gerbv_net
*net
)
224 gerbv_simplified_amacro_t
*ls
= s
;
226 dprintf("Drawing simplified aperture macros:\n");
227 if (usesClearPrimative
)
228 cairo_push_group (cairoTarget
);
231 * This handles the exposure thing in the aperture macro
232 * The exposure is always the first element on stack independent
235 cairo_save (cairoTarget
);
236 cairo_new_path(cairoTarget
);
237 cairo_operator_t oldOperator
= cairo_get_operator (cairoTarget
);
239 if (ls
->type
== MACRO_CIRCLE
) {
241 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
242 darkOperator
, ls
->parameter
[CIRCLE_EXPOSURE
])){
243 cairo_translate (cairoTarget
, ls
->parameter
[CIRCLE_CENTER_X
],
244 ls
->parameter
[CIRCLE_CENTER_Y
]);
246 gerbv_draw_circle (cairoTarget
, ls
->parameter
[CIRCLE_DIAMETER
]);
247 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
249 } else if (ls
->type
== MACRO_OUTLINE
) {
250 int pointCounter
,numberOfPoints
;
251 /* Number of points parameter seems to not include the start point,
252 * so we add one to include the start point.
254 numberOfPoints
= (int) ls
->parameter
[OUTLINE_NUMBER_OF_POINTS
] + 1;
256 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
257 darkOperator
, ls
->parameter
[OUTLINE_EXPOSURE
])){
258 cairo_rotate (cairoTarget
, ls
->parameter
[(numberOfPoints
- 1) * 2 + OUTLINE_ROTATION
] * M_PI
/180.0);
259 cairo_move_to (cairoTarget
, ls
->parameter
[OUTLINE_FIRST_X
], ls
->parameter
[OUTLINE_FIRST_Y
]);
261 for (pointCounter
=0; pointCounter
< numberOfPoints
; pointCounter
++) {
262 cairo_line_to (cairoTarget
, ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_X
],
263 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_Y
]);
265 /* although the gerber specs allow for an open outline,
266 I interpret it to mean the outline should be closed by the
267 rendering softare automatically, since there is no dimension
270 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
272 } else if (ls
->type
== MACRO_POLYGON
) {
273 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
274 darkOperator
, ls
->parameter
[POLYGON_EXPOSURE
])){
275 cairo_translate (cairoTarget
, ls
->parameter
[POLYGON_CENTER_X
],
276 ls
->parameter
[POLYGON_CENTER_Y
]);
277 gerbv_draw_polygon(cairoTarget
, ls
->parameter
[POLYGON_DIAMETER
],
278 ls
->parameter
[POLYGON_NUMBER_OF_POINTS
], ls
->parameter
[POLYGON_ROTATION
]);
279 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
281 } else if (ls
->type
== MACRO_MOIRE
) {
282 gdouble diameter
, gap
;
285 cairo_translate (cairoTarget
, ls
->parameter
[MOIRE_CENTER_X
],
286 ls
->parameter
[MOIRE_CENTER_Y
]);
287 cairo_rotate (cairoTarget
, ls
->parameter
[MOIRE_ROTATION
] * M_PI
/180);
288 diameter
= ls
->parameter
[MOIRE_OUTSIDE_DIAMETER
] - ls
->parameter
[MOIRE_CIRCLE_THICKNESS
];
289 gap
= ls
->parameter
[MOIRE_GAP_WIDTH
] + ls
->parameter
[MOIRE_CIRCLE_THICKNESS
];
290 cairo_set_line_width (cairoTarget
, ls
->parameter
[MOIRE_CIRCLE_THICKNESS
]);
292 for (circleIndex
= 0; circleIndex
< (int)ls
->parameter
[MOIRE_NUMBER_OF_CIRCLES
]; circleIndex
++) {
293 gdouble currentDiameter
= (diameter
- gap
* (float) circleIndex
);
294 gerbv_draw_circle (cairoTarget
, currentDiameter
);
295 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
298 gdouble crosshairRadius
= (ls
->parameter
[MOIRE_CROSSHAIR_LENGTH
] / 2.0);
300 cairo_set_line_width (cairoTarget
, ls
->parameter
[MOIRE_CROSSHAIR_THICKNESS
]);
301 cairo_move_to (cairoTarget
, -crosshairRadius
, 0);
302 cairo_line_to (cairoTarget
, crosshairRadius
, 0);
303 cairo_move_to (cairoTarget
, 0, -crosshairRadius
);
304 cairo_line_to (cairoTarget
, 0, crosshairRadius
);
305 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
306 } else if (ls
->type
== MACRO_THERMAL
) {
308 gdouble startAngle1
, startAngle2
, endAngle1
, endAngle2
;
310 cairo_translate (cairoTarget
, ls
->parameter
[THERMAL_CENTER_X
],
311 ls
->parameter
[THERMAL_CENTER_Y
]);
312 cairo_rotate (cairoTarget
, ls
->parameter
[THERMAL_ROTATION
] * M_PI
/180.0);
313 startAngle1
= atan (ls
->parameter
[THERMAL_CROSSHAIR_THICKNESS
]/ls
->parameter
[THERMAL_INSIDE_DIAMETER
]);
314 endAngle1
= M_PI
/2 - startAngle1
;
315 endAngle2
= atan (ls
->parameter
[THERMAL_CROSSHAIR_THICKNESS
]/ls
->parameter
[THERMAL_OUTSIDE_DIAMETER
]);
316 startAngle2
= M_PI
/2 - endAngle2
;
317 for (i
= 0; i
< 4; i
++) {
318 cairo_arc (cairoTarget
, 0, 0, ls
->parameter
[THERMAL_INSIDE_DIAMETER
]/2.0, startAngle1
, endAngle1
);
319 cairo_rel_line_to (cairoTarget
, 0, ls
->parameter
[THERMAL_CROSSHAIR_THICKNESS
]);
320 cairo_arc_negative (cairoTarget
, 0, 0, ls
->parameter
[THERMAL_OUTSIDE_DIAMETER
]/2.0,
321 startAngle2
, endAngle2
);
322 cairo_rel_line_to (cairoTarget
, -ls
->parameter
[THERMAL_CROSSHAIR_THICKNESS
],0);
323 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
324 cairo_rotate (cairoTarget
, 90 * M_PI
/180);
326 } else if (ls
->type
== MACRO_LINE20
) {
327 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
328 darkOperator
, ls
->parameter
[LINE20_EXPOSURE
])){
329 cairo_set_line_width (cairoTarget
, ls
->parameter
[LINE20_LINE_WIDTH
]);
330 cairo_set_line_cap (cairoTarget
, CAIRO_LINE_CAP_BUTT
);
331 cairo_rotate (cairoTarget
, ls
->parameter
[LINE20_ROTATION
] * M_PI
/180.0);
332 cairo_move_to (cairoTarget
, ls
->parameter
[LINE20_START_X
], ls
->parameter
[LINE20_START_Y
]);
333 cairo_line_to (cairoTarget
, ls
->parameter
[LINE20_END_X
], ls
->parameter
[LINE20_END_Y
]);
334 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
336 } else if (ls
->type
== MACRO_LINE21
) {
337 gdouble halfWidth
, halfHeight
;
339 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
340 darkOperator
, ls
->parameter
[LINE22_EXPOSURE
])){
341 halfWidth
= ls
->parameter
[LINE21_WIDTH
] / 2.0;
342 halfHeight
= ls
->parameter
[LINE21_HEIGHT
] / 2.0;
343 cairo_translate (cairoTarget
, ls
->parameter
[LINE21_CENTER_X
], ls
->parameter
[LINE21_CENTER_Y
]);
344 cairo_rotate (cairoTarget
, ls
->parameter
[LINE21_ROTATION
] * M_PI
/180.0);
345 cairo_rectangle (cairoTarget
, -halfWidth
, -halfHeight
,
346 ls
->parameter
[LINE21_WIDTH
], ls
->parameter
[LINE21_HEIGHT
]);
347 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
349 } else if (ls
->type
== MACRO_LINE22
) {
350 gdouble halfWidth
, halfHeight
;
352 if (draw_update_macro_exposure (cairoTarget
, clearOperator
,
353 darkOperator
, ls
->parameter
[LINE22_EXPOSURE
])){
354 halfWidth
= ls
->parameter
[LINE22_WIDTH
] / 2.0;
355 halfHeight
= ls
->parameter
[LINE22_HEIGHT
] / 2.0;
356 cairo_translate (cairoTarget
, ls
->parameter
[LINE22_LOWER_LEFT_X
],
357 ls
->parameter
[LINE22_LOWER_LEFT_Y
]);
358 cairo_rotate (cairoTarget
, ls
->parameter
[LINE22_ROTATION
] * M_PI
/180.0);
359 cairo_rectangle (cairoTarget
, 0, 0,
360 ls
->parameter
[LINE22_WIDTH
], ls
->parameter
[LINE22_HEIGHT
]);
361 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
366 cairo_set_operator (cairoTarget
, oldOperator
);
367 cairo_restore (cairoTarget
);
370 if (usesClearPrimative
) {
371 cairo_pop_group_to_source (cairoTarget
);
372 cairo_paint (cairoTarget
);
375 } /* gerbv_draw_amacro */
379 draw_apply_netstate_transformation (cairo_t
*cairoTarget
, gerbv_netstate_t
*state
)
381 /* apply scale factor */
382 cairo_scale (cairoTarget
, state
->scaleA
, state
->scaleB
);
384 cairo_translate (cairoTarget
, state
->offsetA
, state
->offsetB
);
386 switch (state
->mirrorState
) {
388 cairo_scale (cairoTarget
, -1, 1);
391 cairo_scale (cairoTarget
, 1, -1);
394 cairo_scale (cairoTarget
, -1, -1);
399 /* finally, apply axis select */
400 if (state
->axisSelect
== SWAPAB
) {
401 /* we do this by rotating 270 (counterclockwise, then mirroring
403 cairo_rotate (cairoTarget
, 3 * M_PI
/ 2);
404 cairo_scale (cairoTarget
, 1, -1);
409 draw_image_to_cairo_target (cairo_t
*cairoTarget
, gerbv_image_t
*image
,
410 gboolean invertLayer
, gdouble pixelWidth
,
411 gchar drawMode
, gerbv_selection_info_t
*selectionInfo
)
413 struct gerbv_net
*net
, *polygonStartNet
=NULL
;
414 double x1
, y1
, x2
, y2
, cp_x
=0, cp_y
=0;
415 int in_parea_fill
= 0,haveDrawnFirstFillPoint
= 0;
416 gdouble p1
, p2
, p3
, p4
, p5
, dx
, dy
;
417 gerbv_netstate_t
*oldState
;
418 gerbv_layer_t
*oldLayer
;
419 int repeat_X
=1, repeat_Y
=1;
420 double repeat_dist_X
= 0, repeat_dist_Y
= 0;
421 int repeat_i
, repeat_j
;
422 cairo_operator_t drawOperatorClear
, drawOperatorDark
;
423 gboolean invertPolarity
= FALSE
;
425 /* do initial justify */
426 cairo_translate (cairoTarget
, image
->info
->imageJustifyOffsetActualA
,
427 image
->info
->imageJustifyOffsetActualB
);
429 /* set the fill rule so aperture holes are cleared correctly */
430 cairo_set_fill_rule (cairoTarget
, CAIRO_FILL_RULE_EVEN_ODD
);
432 cairo_translate (cairoTarget
, image
->info
->offsetA
, image
->info
->offsetB
);
433 /* do image rotation */
434 cairo_rotate (cairoTarget
, image
->info
->imageRotation
);
435 /* load in polarity operators depending on the image polarity */
436 invertPolarity
= invertLayer
;
437 if (image
->info
->polarity
== NEGATIVE
)
438 invertPolarity
= !invertPolarity
;
439 if (invertPolarity
) {
440 drawOperatorClear
= CAIRO_OPERATOR_OVER
;
441 drawOperatorDark
= CAIRO_OPERATOR_CLEAR
;
442 cairo_set_operator (cairoTarget
, CAIRO_OPERATOR_OVER
);
443 cairo_paint (cairoTarget
);
444 cairo_set_operator (cairoTarget
, CAIRO_OPERATOR_CLEAR
);
447 drawOperatorClear
= CAIRO_OPERATOR_CLEAR
;
448 drawOperatorDark
= CAIRO_OPERATOR_OVER
;
450 /* next, push two cairo states to simulate the first layer and netstate
451 translations (these will be popped when another layer or netstate is
454 cairo_save (cairoTarget
);
455 cairo_save (cairoTarget
);
456 /* store the current layer and netstate so we know when they change */
457 oldLayer
= image
->layers
;
458 oldState
= image
->states
;
460 for (net
= image
->netlist
->next
; net
!= NULL
; net
= net
->next
) {
462 /* check if this is a new layer */
463 if (net
->layer
!= oldLayer
){
464 /* it's a new layer, so recalculate the new transformation matrix
466 cairo_restore (cairoTarget
);
467 cairo_restore (cairoTarget
);
468 cairo_save (cairoTarget
);
469 /* do any rotations */
470 cairo_rotate (cairoTarget
, net
->layer
->rotation
);
471 /* handle the layer polarity */
472 if ((net
->layer
->polarity
== CLEAR
)) {
473 cairo_set_operator (cairoTarget
, drawOperatorClear
);
476 cairo_set_operator (cairoTarget
, drawOperatorDark
);
478 /* check for changes to step and repeat */
479 repeat_X
= net
->layer
->stepAndRepeat
.X
;
480 repeat_Y
= net
->layer
->stepAndRepeat
.Y
;
481 repeat_dist_X
= net
->layer
->stepAndRepeat
.dist_X
;
482 repeat_dist_Y
= net
->layer
->stepAndRepeat
.dist_Y
;
483 /* draw any knockout areas */
484 if (net
->layer
->knockout
.firstInstance
== TRUE
) {
485 cairo_operator_t oldOperator
= cairo_get_operator (cairoTarget
);
486 if (net
->layer
->knockout
.polarity
== CLEAR
) {
487 cairo_set_operator (cairoTarget
, drawOperatorClear
);
490 cairo_set_operator (cairoTarget
, drawOperatorDark
);
492 cairo_new_path (cairoTarget
);
493 cairo_rectangle (cairoTarget
, net
->layer
->knockout
.lowerLeftX
- net
->layer
->knockout
.border
,
494 net
->layer
->knockout
.lowerLeftY
- net
->layer
->knockout
.border
,
495 net
->layer
->knockout
.width
+ (net
->layer
->knockout
.border
*2),
496 net
->layer
->knockout
.height
+ (net
->layer
->knockout
.border
*2));
497 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
498 cairo_set_operator (cairoTarget
, oldOperator
);
500 /* finally, reapply old netstate transformation */
501 cairo_save (cairoTarget
);
502 draw_apply_netstate_transformation (cairoTarget
, net
->state
);
503 oldLayer
= net
->layer
;
505 /* check if this is a new netstate */
506 if (net
->state
!= oldState
){
507 /* pop the transformation matrix back to the "pre-state" state and
509 cairo_restore (cairoTarget
);
510 cairo_save (cairoTarget
);
511 /* it's a new state, so recalculate the new transformation matrix
513 draw_apply_netstate_transformation (cairoTarget
, net
->state
);
514 oldState
= net
->state
;
516 /* if we are only drawing from the selection buffer, search if this net is
518 if (drawMode
== DRAW_SELECTIONS
) {
519 /* this flag makes sure we don't draw any unintentional polygons...
520 if we've successfully entered a polygon (the first net matches, and
521 we don't want to check the nets inside the polygon) then
522 polygonStartNet will be set */
523 if (!polygonStartNet
) {
525 gboolean foundNet
= FALSE
;
527 for (i
=0; i
<selectionInfo
->selectedNodeArray
->len
; i
++){
528 gerbv_selection_item_t sItem
= g_array_index (selectionInfo
->selectedNodeArray
,
529 gerbv_selection_item_t
, i
);
530 if (sItem
.net
== net
)
538 for(repeat_i
= 0; repeat_i
< repeat_X
; repeat_i
++) {
539 for(repeat_j
= 0; repeat_j
< repeat_Y
; repeat_j
++) {
540 double sr_x
= repeat_i
* repeat_dist_X
;
541 double sr_y
= repeat_j
* repeat_dist_Y
;
543 x1
= net
->start_x
+ sr_x
;
544 y1
= net
->start_y
+ sr_y
;
545 x2
= net
->stop_x
+ sr_x
;
546 y2
= net
->stop_y
+ sr_y
;
548 /* translate circular x,y data as well */
550 cp_x
= net
->cirseg
->cp_x
+ sr_x
;
551 cp_y
= net
->cirseg
->cp_y
+ sr_y
;
554 /* render any labels attached to this net */
555 /* NOTE: this is currently only used on PNP files, so we may
556 make some assumptions here... */
558 cairo_set_font_size (cairoTarget
, 0.05);
559 cairo_save (cairoTarget
);
561 cairo_move_to (cairoTarget
, x1
, y1
);
562 cairo_scale (cairoTarget
, 1, -1);
563 cairo_show_text (cairoTarget
, net
->label
->str
);
564 cairo_restore (cairoTarget
);
567 * Polygon Area Fill routines
569 switch (net
->interpolation
) {
572 haveDrawnFirstFillPoint
= FALSE
;
573 /* save the first net in the polygon as the "ID" net pointer
574 in case we are saving this net to the selection array */
575 polygonStartNet
= net
;
576 cairo_new_path(cairoTarget
);
579 cairo_close_path(cairoTarget
);
580 /* turn off anti-aliasing for polygons, since it shows seams
581 with adjacent polygons (usually on PCB ground planes) */
582 cairo_antialias_t oldAlias
= cairo_get_antialias (cairoTarget
);
583 cairo_set_antialias (cairoTarget
, CAIRO_ANTIALIAS_NONE
);
584 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, polygonStartNet
);
585 cairo_set_antialias (cairoTarget
, oldAlias
);
587 polygonStartNet
= NULL
;
589 /* make sure we completely skip over any deleted nodes */
596 if (!haveDrawnFirstFillPoint
) {
597 cairo_move_to (cairoTarget
, x2
,y2
);
598 haveDrawnFirstFillPoint
=TRUE
;
601 switch (net
->interpolation
) {
606 cairo_line_to (cairoTarget
, x2
,y2
);
610 if (net
->cirseg
->angle2
> net
->cirseg
->angle1
) {
611 cairo_arc (cairoTarget
, cp_x
, cp_y
, net
->cirseg
->width
/2.0,
612 net
->cirseg
->angle1
* M_PI
/180,net
->cirseg
->angle2
* M_PI
/180);
615 cairo_arc_negative (cairoTarget
, cp_x
, cp_y
, net
->cirseg
->width
/2.0,
616 net
->cirseg
->angle1
* M_PI
/180,net
->cirseg
->angle2
* M_PI
/180);
626 * If aperture state is off we allow use of undefined apertures.
627 * This happens when gerber files starts, but hasn't decided on
628 * which aperture to use.
630 if (image
->aperture
[net
->aperture
] == NULL
) {
631 if (net
->aperture_state
!= OFF
)
632 GERB_MESSAGE("Aperture [%d] is not defined\n", net
->aperture
);
635 switch (net
->aperture_state
) {
637 /* if the aperture width is truly 0, then render as a 1 pixel width
638 line. 0 diameter apertures are used by some programs to draw labels,
639 etc, and they are rendered by other programs as 1 pixel wide */
640 /* NOTE: also, make sure all lines are at least 1 pixel wide, so they
641 always show up at low zoom levels */
642 if (image
->aperture
[net
->aperture
]->parameter
[0] > pixelWidth
)
643 cairo_set_line_width (cairoTarget
, image
->aperture
[net
->aperture
]->parameter
[0]);
645 cairo_set_line_width (cairoTarget
, pixelWidth
);
646 switch (net
->interpolation
) {
651 cairo_set_line_cap (cairoTarget
, CAIRO_LINE_CAP_ROUND
);
652 switch (image
->aperture
[net
->aperture
]->type
) {
654 cairo_move_to (cairoTarget
, x1
,y1
);
655 cairo_line_to (cairoTarget
, x2
,y2
);
656 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
659 dx
= (image
->aperture
[net
->aperture
]->parameter
[0]/ 2);
660 dy
= (image
->aperture
[net
->aperture
]->parameter
[1]/ 2);
665 cairo_new_path(cairoTarget
);
666 cairo_move_to (cairoTarget
, x1
- dx
, y1
- dy
);
667 cairo_line_to (cairoTarget
, x1
- dx
, y1
+ dy
);
668 cairo_line_to (cairoTarget
, x2
- dx
, y2
+ dy
);
669 cairo_line_to (cairoTarget
, x2
+ dx
, y2
+ dy
);
670 cairo_line_to (cairoTarget
, x2
+ dx
, y2
- dy
);
671 cairo_line_to (cairoTarget
, x1
+ dx
, y1
- dy
);
672 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
674 /* for now, just render ovals or polygons like a circle */
677 cairo_move_to (cairoTarget
, x1
,y1
);
678 cairo_line_to (cairoTarget
, x2
,y2
);
679 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
681 /* macros can only be flashed, so ignore any that might be here */
688 /* cairo doesn't have a function to draw oval arcs, so we must
689 * draw an arc and stretch it by scaling different x and y values
691 cairo_new_path(cairoTarget
);
692 if (image
->aperture
[net
->aperture
]->type
== RECTANGLE
) {
693 cairo_set_line_cap (cairoTarget
, CAIRO_LINE_CAP_SQUARE
);
696 cairo_set_line_cap (cairoTarget
, CAIRO_LINE_CAP_ROUND
);
698 cairo_save (cairoTarget
);
699 cairo_translate(cairoTarget
, cp_x
, cp_y
);
700 cairo_scale (cairoTarget
, net
->cirseg
->width
, net
->cirseg
->height
);
701 if (net
->cirseg
->angle2
> net
->cirseg
->angle1
) {
702 cairo_arc (cairoTarget
, 0.0, 0.0, 0.5, net
->cirseg
->angle1
* M_PI
/180,
703 net
->cirseg
->angle2
* M_PI
/180);
706 cairo_arc_negative (cairoTarget
, 0.0, 0.0, 0.5, net
->cirseg
->angle1
* M_PI
/180,
707 net
->cirseg
->angle2
* M_PI
/180);
709 cairo_restore (cairoTarget
);
710 draw_stroke (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
719 p1
= image
->aperture
[net
->aperture
]->parameter
[0];
720 p2
= image
->aperture
[net
->aperture
]->parameter
[1];
721 p3
= image
->aperture
[net
->aperture
]->parameter
[2];
722 p4
= image
->aperture
[net
->aperture
]->parameter
[3];
723 p5
= image
->aperture
[net
->aperture
]->parameter
[4];
725 cairo_save (cairoTarget
);
726 cairo_translate (cairoTarget
, x2
, y2
);
728 switch (image
->aperture
[net
->aperture
]->type
) {
730 gerbv_draw_circle(cairoTarget
, p1
);
731 gerbv_draw_aperature_hole (cairoTarget
, p2
, p3
);
734 gerbv_draw_rectangle(cairoTarget
, p1
, p2
);
735 gerbv_draw_aperature_hole (cairoTarget
, p3
, p4
);
738 gerbv_draw_oblong(cairoTarget
, p1
, p2
);
739 gerbv_draw_aperature_hole (cairoTarget
, p3
, p4
);
742 gerbv_draw_polygon(cairoTarget
, p1
, p2
, p3
);
743 gerbv_draw_aperature_hole (cairoTarget
, p4
, p5
);
746 gerbv_draw_amacro(cairoTarget
, drawOperatorClear
, drawOperatorDark
,
747 image
->aperture
[net
->aperture
]->simplified
,
748 (int) image
->aperture
[net
->aperture
]->parameter
[0],
749 drawMode
, selectionInfo
, image
, net
);
752 GERB_MESSAGE("Unknown aperture type\n");
755 /* and finally fill the path */
756 draw_fill (cairoTarget
, drawMode
, selectionInfo
, image
, net
);
757 cairo_restore (cairoTarget
);
760 GERB_MESSAGE("Unknown aperture state\n");
767 /* restore the initial two state saves (one for layer, one for netstate)*/
768 cairo_restore (cairoTarget
);
769 cairo_restore (cairoTarget
);