4 #include "data.h" /* For global "PCB" variable */
9 common_draw_pcb_line (hidGC gc
, LineType
*line
)
11 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
12 if (TEST_FLAG (THINDRAWFLAG
, PCB
))
13 gui
->graphics
->set_line_width (gc
, 0);
15 gui
->graphics
->set_line_width (gc
, line
->Thickness
);
17 gui
->graphics
->draw_line (gc
,
18 line
->Point1
.X
, line
->Point1
.Y
,
19 line
->Point2
.X
, line
->Point2
.Y
);
23 common_draw_pcb_arc (hidGC gc
, ArcType
*arc
)
28 if (TEST_FLAG (THINDRAWFLAG
, PCB
))
29 gui
->graphics
->set_line_width (gc
, 0);
31 gui
->graphics
->set_line_width (gc
, arc
->Thickness
);
32 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
34 gui
->graphics
->draw_arc (gc
, arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
38 fill_contour (hidGC gc
, PLINE
*pl
)
40 Coord
*x
, *y
, n
, i
= 0;
44 x
= (Coord
*)malloc (n
* sizeof (*x
));
45 y
= (Coord
*)malloc (n
* sizeof (*y
));
47 for (v
= &pl
->head
; i
< n
; v
= v
->next
)
53 gui
->graphics
->fill_polygon (gc
, n
, x
, y
);
60 thindraw_contour (hidGC gc
, PLINE
*pl
)
66 gui
->graphics
->set_line_width (gc
, 0);
67 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
69 /* If the contour is round, use an arc drawing routine. */
72 gui
->graphics
->draw_arc (gc
, pl
->cx
, pl
->cy
, pl
->radius
, pl
->radius
, 0, 360);
76 /* Need at least two points in the contour */
77 if (pl
->head
.next
== NULL
)
80 last_x
= pl
->head
.point
[0];
81 last_y
= pl
->head
.point
[1];
89 gui
->graphics
->draw_line (gc
, last_x
, last_y
, this_x
, this_y
);
90 // gui->graphics->fill_circle (gc, this_x, this_y, 30);
95 while ((v
= v
->next
) != pl
->head
.next
);
99 fill_contour_cb (PLINE
*pl
, void *user_data
)
101 hidGC gc
= (hidGC
)user_data
;
102 PLINE
*local_pl
= pl
;
104 fill_contour (gc
, pl
);
105 poly_FreeContours (&local_pl
);
109 fill_clipped_contour (hidGC gc
, PLINE
*pl
, const BoxType
*clip_box
)
113 POLYAREA
*piece_poly
;
114 POLYAREA
*clipped_pieces
;
115 POLYAREA
*draw_piece
;
118 clip_poly
= RectPoly (clip_box
->X1
, clip_box
->X2
,
119 clip_box
->Y1
, clip_box
->Y2
);
120 poly_CopyContour (&pl_copy
, pl
);
121 piece_poly
= poly_Create ();
122 poly_InclContour (piece_poly
, pl_copy
);
123 x
= poly_Boolean_free (piece_poly
, clip_poly
,
124 &clipped_pieces
, PBO_ISECT
);
125 if (x
!= err_ok
|| clipped_pieces
== NULL
)
128 draw_piece
= clipped_pieces
;
131 /* NB: The polygon won't have any holes in it */
132 fill_contour (gc
, draw_piece
->contours
);
134 while ((draw_piece
= draw_piece
->f
) != clipped_pieces
);
135 poly_Free (&clipped_pieces
);
138 /* If at least 50% of the bounding box of the polygon is on the screen,
139 * lets compute the complete no-holes polygon.
141 #define BOUNDS_INSIDE_CLIP_THRESHOLD 0.5
143 should_compute_no_holes (PolygonType
*poly
, const BoxType
*clip_box
)
145 Coord x1
, x2
, y1
, y2
;
146 double poly_bounding_area
;
147 double clipped_poly_area
;
149 /* If there is no passed clip box, compute the whole thing */
150 if (clip_box
== NULL
)
153 x1
= MAX (poly
->BoundingBox
.X1
, clip_box
->X1
);
154 x2
= MIN (poly
->BoundingBox
.X2
, clip_box
->X2
);
155 y1
= MAX (poly
->BoundingBox
.Y1
, clip_box
->Y1
);
156 y2
= MIN (poly
->BoundingBox
.Y2
, clip_box
->Y2
);
158 /* Check if the polygon is outside the clip box */
159 if ((x2
<= x1
) || (y2
<= y1
))
162 poly_bounding_area
= (double)(poly
->BoundingBox
.X2
- poly
->BoundingBox
.X1
) *
163 (double)(poly
->BoundingBox
.Y2
- poly
->BoundingBox
.Y1
);
165 clipped_poly_area
= (double)(x2
- x1
) * (double)(y2
- y1
);
167 if (clipped_poly_area
/ poly_bounding_area
>= BOUNDS_INSIDE_CLIP_THRESHOLD
)
172 #undef BOUNDS_INSIDE_CLIP_THRESHOLD
175 common_fill_pcb_polygon (hidGC gc
, PolygonType
*poly
, const BoxType
*clip_box
)
177 if (!poly
->NoHolesValid
)
179 /* If enough of the polygon is on-screen, compute the entire
180 * NoHoles version and cache it for later rendering, otherwise
181 * just compute what we need to render now.
183 if (should_compute_no_holes (poly
, clip_box
))
184 ComputeNoHoles (poly
);
186 NoHolesPolygonDicer (poly
, clip_box
, fill_contour_cb
, gc
);
188 if (poly
->NoHolesValid
&& poly
->NoHoles
)
192 for (pl
= poly
->NoHoles
; pl
!= NULL
; pl
= pl
->next
)
194 if (clip_box
== NULL
)
195 fill_contour (gc
, pl
);
197 fill_clipped_contour (gc
, pl
, clip_box
);
201 /* Draw other parts of the polygon if fullpoly flag is set */
202 /* NB: No "NoHoles" cache for these */
203 if (TEST_FLAG (FULLPOLYFLAG
, poly
))
205 PolygonType p
= *poly
;
207 for (p
.Clipped
= poly
->Clipped
->f
;
208 p
.Clipped
!= poly
->Clipped
;
209 p
.Clipped
= p
.Clipped
->f
)
210 NoHolesPolygonDicer (&p
, clip_box
, fill_contour_cb
, gc
);
215 thindraw_hole_cb (PLINE
*pl
, void *user_data
)
217 hidGC gc
= (hidGC
)user_data
;
218 thindraw_contour (gc
, pl
);
223 common_thindraw_pcb_polygon (hidGC gc
, PolygonType
*poly
,
224 const BoxType
*clip_box
)
226 thindraw_contour (gc
, poly
->Clipped
->contours
);
227 PolygonHoles (poly
, clip_box
, thindraw_hole_cb
, gc
);
231 common_thindraw_pcb_pad (hidGC gc
, PadType
*pad
, bool clear
, bool mask
)
233 Coord w
= clear
? (mask
? pad
->Mask
234 : pad
->Thickness
+ pad
->Clearance
)
236 Coord x1
, y1
, x2
, y2
;
242 if (x1
> x2
|| y1
> y2
)
246 x1
= x2
; x2
= temp_x
;
247 y1
= y2
; y2
= temp_y
;
249 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
250 gui
->graphics
->set_line_width (gc
, 0);
251 if (TEST_FLAG (SQUAREFLAG
, pad
))
253 /* slanted square pad */
254 double tx
, ty
, theta
;
256 if (x1
== x2
&& y1
== y2
)
259 theta
= atan2 (y2
- y1
, x2
- x1
);
261 /* T is a vector half a thickness long, in the direction of
262 one of the corners. */
263 tx
= t
* cos (theta
+ M_PI
/ 4) * sqrt (2.0);
264 ty
= t
* sin (theta
+ M_PI
/ 4) * sqrt (2.0);
266 gui
->graphics
->draw_line (gc
, x1
- tx
, y1
- ty
, x2
+ ty
, y2
- tx
);
267 gui
->graphics
->draw_line (gc
, x2
+ ty
, y2
- tx
, x2
+ tx
, y2
+ ty
);
268 gui
->graphics
->draw_line (gc
, x2
+ tx
, y2
+ ty
, x1
- ty
, y1
+ tx
);
269 gui
->graphics
->draw_line (gc
, x1
- ty
, y1
+ tx
, x1
- tx
, y1
- ty
);
271 else if (x1
== x2
&& y1
== y2
)
273 gui
->graphics
->draw_arc (gc
, x1
, y1
, t
, t
, 0, 360);
277 /* Slanted round-end pads. */
278 Coord dx
, dy
, ox
, oy
;
283 h
= t
/ sqrt (SQUARE (dx
) + SQUARE (dy
));
284 ox
= dy
* h
+ 0.5 * SGN (dy
);
285 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
287 gui
->graphics
->draw_line (gc
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
289 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
291 Angle angle
= atan2 (dx
, dy
) * 57.295779;
292 gui
->graphics
->draw_line (gc
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
293 gui
->graphics
->draw_arc (gc
, x1
, y1
, t
, t
, angle
- 180, 180);
294 gui
->graphics
->draw_arc (gc
, x2
, y2
, t
, t
, angle
, 180);
300 common_fill_pcb_pad (hidGC gc
, PadType
*pad
, bool clear
, bool mask
)
302 Coord w
= clear
? (mask
? pad
->Mask
303 : pad
->Thickness
+ pad
->Clearance
)
306 if (pad
->Point1
.X
== pad
->Point2
.X
&&
307 pad
->Point1
.Y
== pad
->Point2
.Y
)
309 if (TEST_FLAG (SQUAREFLAG
, pad
))
312 l
= pad
->Point1
.X
- w
/ 2;
313 b
= pad
->Point1
.Y
- w
/ 2;
316 gui
->graphics
->fill_rect (gc
, l
, b
, r
, t
);
320 gui
->graphics
->fill_circle (gc
, pad
->Point1
.X
, pad
->Point1
.Y
, w
/ 2);
325 gui
->graphics
->set_line_cap (gc
, TEST_FLAG (SQUAREFLAG
, pad
) ?
326 Square_Cap
: Round_Cap
);
327 gui
->graphics
->set_line_width (gc
, w
);
329 gui
->graphics
->draw_line (gc
, pad
->Point1
.X
, pad
->Point1
.Y
,
330 pad
->Point2
.X
, pad
->Point2
.Y
);
334 /* ---------------------------------------------------------------------------
336 * x and y are already in display coordinates
337 * the points are numbered:
355 draw_octagon_poly (hidGC gc
, Coord X
, Coord Y
,
356 Coord Thickness
, bool thin_draw
)
358 static FloatPolyType p
[8] = {
359 { 0.5, -TAN_22_5_DEGREE_2
},
360 { TAN_22_5_DEGREE_2
, -0.5 },
361 {-TAN_22_5_DEGREE_2
, -0.5 },
362 {-0.5, -TAN_22_5_DEGREE_2
},
363 {-0.5, TAN_22_5_DEGREE_2
},
364 {-TAN_22_5_DEGREE_2
, 0.5 },
365 { TAN_22_5_DEGREE_2
, 0.5 },
366 { 0.5, TAN_22_5_DEGREE_2
}
368 static int special_size
= 0;
369 static int scaled_x
[8];
370 static int scaled_y
[8];
375 if (Thickness
!= special_size
)
377 special_size
= Thickness
;
378 for (i
= 0; i
< 8; i
++)
380 scaled_x
[i
] = p
[i
].X
* special_size
;
381 scaled_y
[i
] = p
[i
].Y
* special_size
;
384 /* add line offset */
385 for (i
= 0; i
< 8; i
++)
387 polygon_x
[i
] = X
+ scaled_x
[i
];
388 polygon_y
[i
] = Y
+ scaled_y
[i
];
394 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
395 gui
->graphics
->set_line_width (gc
, 0);
396 polygon_x
[8] = X
+ scaled_x
[0];
397 polygon_y
[8] = Y
+ scaled_y
[0];
398 for (i
= 0; i
< 8; i
++)
399 gui
->graphics
->draw_line (gc
, polygon_x
[i
], polygon_y
[i
],
400 polygon_x
[i
+ 1], polygon_y
[i
+ 1]);
403 gui
->graphics
->fill_polygon (gc
, 8, polygon_x
, polygon_y
);
407 common_fill_pcb_pv (hidGC fg_gc
, hidGC bg_gc
, PinType
*pv
, bool drawHole
, bool mask
)
409 Coord w
= mask
? pv
->Mask
: pv
->Thickness
;
412 if (TEST_FLAG (HOLEFLAG
, pv
))
415 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, r
);
418 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, r
);
419 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
420 gui
->graphics
->set_line_width (fg_gc
, 0);
421 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
426 if (TEST_FLAG (SQUAREFLAG
, pv
))
433 gui
->graphics
->fill_rect (fg_gc
, l
, b
, r
, t
);
435 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
436 draw_octagon_poly (fg_gc
, pv
->X
, pv
->Y
, w
, false);
437 else /* draw a round pin or via */
438 gui
->graphics
->fill_circle (fg_gc
, pv
->X
, pv
->Y
, r
);
440 /* and the drilling hole (which is always round) */
442 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, pv
->DrillingHole
/ 2);
446 common_thindraw_pcb_pv (hidGC fg_gc
, hidGC bg_gc
, PinType
*pv
, bool drawHole
, bool mask
)
448 Coord w
= mask
? pv
->Mask
: pv
->Thickness
;
451 if (TEST_FLAG (HOLEFLAG
, pv
))
454 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
457 r
= pv
->DrillingHole
/ 2;
458 gui
->graphics
->set_line_cap (bg_gc
, Round_Cap
);
459 gui
->graphics
->set_line_width (bg_gc
, 0);
460 gui
->graphics
->draw_arc (bg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
465 if (TEST_FLAG (SQUAREFLAG
, pv
))
472 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
473 gui
->graphics
->set_line_width (fg_gc
, 0);
474 gui
->graphics
->draw_line (fg_gc
, r
, t
, r
, b
);
475 gui
->graphics
->draw_line (fg_gc
, l
, t
, l
, b
);
476 gui
->graphics
->draw_line (fg_gc
, r
, t
, l
, t
);
477 gui
->graphics
->draw_line (fg_gc
, r
, b
, l
, b
);
480 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
482 draw_octagon_poly (fg_gc
, pv
->X
, pv
->Y
, w
, true);
484 else /* draw a round pin or via */
486 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
487 gui
->graphics
->set_line_width (fg_gc
, 0);
488 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
491 /* and the drilling hole (which is always round */
494 gui
->graphics
->set_line_cap (bg_gc
, Round_Cap
);
495 gui
->graphics
->set_line_width (bg_gc
, 0);
496 gui
->graphics
->draw_arc (bg_gc
, pv
->X
, pv
->Y
, pv
->DrillingHole
/ 2,
497 pv
->DrillingHole
/ 2, 0, 360);
502 common_draw_helpers_init (HID_DRAW
*graphics
)
504 graphics
->draw_pcb_line
= common_draw_pcb_line
;
505 graphics
->draw_pcb_arc
= common_draw_pcb_arc
;
507 graphics
->fill_pcb_polygon
= common_fill_pcb_polygon
;
508 graphics
->thindraw_pcb_polygon
= common_thindraw_pcb_polygon
;
509 graphics
->fill_pcb_pad
= common_fill_pcb_pad
;
510 graphics
->thindraw_pcb_pad
= common_thindraw_pcb_pad
;
511 graphics
->fill_pcb_pv
= common_fill_pcb_pv
;
512 graphics
->thindraw_pcb_pv
= common_thindraw_pcb_pv
;