4 #include "data.h" /* For global "PCB" variable */
5 #include "rotate.h" /* For RotateLineLowLevel() */
10 common_draw_pcb_line (hidGC gc
, LineType
*line
)
12 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
13 if (TEST_FLAG (THINDRAWFLAG
, PCB
))
14 gui
->graphics
->set_line_width (gc
, 0);
16 gui
->graphics
->set_line_width (gc
, line
->Thickness
);
18 gui
->graphics
->draw_line (gc
,
19 line
->Point1
.X
, line
->Point1
.Y
,
20 line
->Point2
.X
, line
->Point2
.Y
);
24 common_draw_pcb_arc (hidGC gc
, ArcType
*arc
)
29 if (TEST_FLAG (THINDRAWFLAG
, PCB
))
30 gui
->graphics
->set_line_width (gc
, 0);
32 gui
->graphics
->set_line_width (gc
, arc
->Thickness
);
33 gui
->graphics
->set_line_cap (gc
, Trace_Cap
);
35 gui
->graphics
->draw_arc (gc
, arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
38 /* ---------------------------------------------------------------------------
39 * drawing routine for text objects
42 common_draw_pcb_text (hidGC gc
, TextType
*Text
, Coord min_line_width
)
45 unsigned char *string
= (unsigned char *) Text
->TextString
;
47 FontType
*font
= &PCB
->Font
;
49 while (string
&& *string
)
51 /* draw lines if symbol is valid and data is present */
52 if (*string
<= MAX_FONTPOSITION
&& font
->Symbol
[*string
].Valid
)
54 LineType
*line
= font
->Symbol
[*string
].Line
;
57 for (n
= font
->Symbol
[*string
].LineN
; n
; n
--, line
++)
59 /* create one line, scale, move, rotate and swap it */
61 newline
.Point1
.X
= SCALE_TEXT (newline
.Point1
.X
+ x
, Text
->Scale
);
62 newline
.Point1
.Y
= SCALE_TEXT (newline
.Point1
.Y
, Text
->Scale
);
63 newline
.Point2
.X
= SCALE_TEXT (newline
.Point2
.X
+ x
, Text
->Scale
);
64 newline
.Point2
.Y
= SCALE_TEXT (newline
.Point2
.Y
, Text
->Scale
);
65 newline
.Thickness
= SCALE_TEXT (newline
.Thickness
, Text
->Scale
/ 2);
66 if (newline
.Thickness
< min_line_width
)
67 newline
.Thickness
= min_line_width
;
69 RotateLineLowLevel (&newline
, 0, 0, Text
->Direction
);
71 /* the labels of SMD objects on the bottom
72 * side haven't been swapped yet, only their offset
74 if (TEST_FLAG (ONSOLDERFLAG
, Text
))
76 newline
.Point1
.X
= SWAP_SIGN_X (newline
.Point1
.X
);
77 newline
.Point1
.Y
= SWAP_SIGN_Y (newline
.Point1
.Y
);
78 newline
.Point2
.X
= SWAP_SIGN_X (newline
.Point2
.X
);
79 newline
.Point2
.Y
= SWAP_SIGN_Y (newline
.Point2
.Y
);
81 /* add offset and draw line */
82 newline
.Point1
.X
+= Text
->X
;
83 newline
.Point1
.Y
+= Text
->Y
;
84 newline
.Point2
.X
+= Text
->X
;
85 newline
.Point2
.Y
+= Text
->Y
;
86 gui
->graphics
->draw_pcb_line (gc
, &newline
);
89 /* move on to next cursor position */
90 x
+= (font
->Symbol
[*string
].Width
+ font
->Symbol
[*string
].Delta
);
94 /* the default symbol is a filled box */
95 BoxType defaultsymbol
= PCB
->Font
.DefaultSymbol
;
96 Coord size
= (defaultsymbol
.X2
- defaultsymbol
.X1
) * 6 / 5;
98 defaultsymbol
.X1
= SCALE_TEXT (defaultsymbol
.X1
+ x
, Text
->Scale
);
99 defaultsymbol
.Y1
= SCALE_TEXT (defaultsymbol
.Y1
, Text
->Scale
);
100 defaultsymbol
.X2
= SCALE_TEXT (defaultsymbol
.X2
+ x
, Text
->Scale
);
101 defaultsymbol
.Y2
= SCALE_TEXT (defaultsymbol
.Y2
, Text
->Scale
);
103 RotateBoxLowLevel (&defaultsymbol
, 0, 0, Text
->Direction
);
105 /* add offset and draw box */
106 defaultsymbol
.X1
+= Text
->X
;
107 defaultsymbol
.Y1
+= Text
->Y
;
108 defaultsymbol
.X2
+= Text
->X
;
109 defaultsymbol
.Y2
+= Text
->Y
;
110 gui
->graphics
->fill_rect (gc
,
111 defaultsymbol
.X1
, defaultsymbol
.Y1
,
112 defaultsymbol
.X2
, defaultsymbol
.Y2
);
114 /* move on to next cursor position */
122 fill_contour (hidGC gc
, PLINE
*pl
)
124 Coord
*x
, *y
, n
, i
= 0;
128 x
= (Coord
*)malloc (n
* sizeof (*x
));
129 y
= (Coord
*)malloc (n
* sizeof (*y
));
131 for (v
= &pl
->head
; i
< n
; v
= v
->next
)
134 y
[i
++] = v
->point
[1];
137 gui
->graphics
->fill_polygon (gc
, n
, x
, y
);
144 thindraw_contour (hidGC gc
, PLINE
*pl
)
147 Coord last_x
, last_y
;
148 Coord this_x
, this_y
;
150 gui
->graphics
->set_line_width (gc
, 0);
151 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
153 /* If the contour is round, use an arc drawing routine. */
156 gui
->graphics
->draw_arc (gc
, pl
->cx
, pl
->cy
, pl
->radius
, pl
->radius
, 0, 360);
160 /* Need at least two points in the contour */
161 if (pl
->head
.next
== NULL
)
164 last_x
= pl
->head
.point
[0];
165 last_y
= pl
->head
.point
[1];
170 this_x
= v
->point
[0];
171 this_y
= v
->point
[1];
173 gui
->graphics
->draw_line (gc
, last_x
, last_y
, this_x
, this_y
);
174 // gui->graphics->fill_circle (gc, this_x, this_y, 30);
179 while ((v
= v
->next
) != pl
->head
.next
);
183 fill_contour_cb (PLINE
*pl
, void *user_data
)
185 hidGC gc
= (hidGC
)user_data
;
186 PLINE
*local_pl
= pl
;
188 fill_contour (gc
, pl
);
189 poly_FreeContours (&local_pl
);
193 fill_clipped_contour (hidGC gc
, PLINE
*pl
, const BoxType
*clip_box
)
197 POLYAREA
*piece_poly
;
198 POLYAREA
*clipped_pieces
;
199 POLYAREA
*draw_piece
;
202 clip_poly
= RectPoly (clip_box
->X1
, clip_box
->X2
,
203 clip_box
->Y1
, clip_box
->Y2
);
204 poly_CopyContour (&pl_copy
, pl
);
205 piece_poly
= poly_Create ();
206 poly_InclContour (piece_poly
, pl_copy
);
207 x
= poly_Boolean_free (piece_poly
, clip_poly
,
208 &clipped_pieces
, PBO_ISECT
);
209 if (x
!= err_ok
|| clipped_pieces
== NULL
)
212 draw_piece
= clipped_pieces
;
215 /* NB: The polygon won't have any holes in it */
216 fill_contour (gc
, draw_piece
->contours
);
218 while ((draw_piece
= draw_piece
->f
) != clipped_pieces
);
219 poly_Free (&clipped_pieces
);
222 /* If at least 50% of the bounding box of the polygon is on the screen,
223 * lets compute the complete no-holes polygon.
225 #define BOUNDS_INSIDE_CLIP_THRESHOLD 0.5
227 should_compute_no_holes (PolygonType
*poly
, const BoxType
*clip_box
)
229 Coord x1
, x2
, y1
, y2
;
230 double poly_bounding_area
;
231 double clipped_poly_area
;
233 /* If there is no passed clip box, compute the whole thing */
234 if (clip_box
== NULL
)
237 x1
= MAX (poly
->BoundingBox
.X1
, clip_box
->X1
);
238 x2
= MIN (poly
->BoundingBox
.X2
, clip_box
->X2
);
239 y1
= MAX (poly
->BoundingBox
.Y1
, clip_box
->Y1
);
240 y2
= MIN (poly
->BoundingBox
.Y2
, clip_box
->Y2
);
242 /* Check if the polygon is outside the clip box */
243 if ((x2
<= x1
) || (y2
<= y1
))
246 poly_bounding_area
= (double)(poly
->BoundingBox
.X2
- poly
->BoundingBox
.X1
) *
247 (double)(poly
->BoundingBox
.Y2
- poly
->BoundingBox
.Y1
);
249 clipped_poly_area
= (double)(x2
- x1
) * (double)(y2
- y1
);
251 if (clipped_poly_area
/ poly_bounding_area
>= BOUNDS_INSIDE_CLIP_THRESHOLD
)
256 #undef BOUNDS_INSIDE_CLIP_THRESHOLD
259 common_fill_pcb_polygon (hidGC gc
, PolygonType
*poly
, const BoxType
*clip_box
)
261 if (!poly
->NoHolesValid
)
263 /* If enough of the polygon is on-screen, compute the entire
264 * NoHoles version and cache it for later rendering, otherwise
265 * just compute what we need to render now.
267 if (should_compute_no_holes (poly
, clip_box
))
268 ComputeNoHoles (poly
);
270 NoHolesPolygonDicer (poly
, clip_box
, fill_contour_cb
, gc
);
272 if (poly
->NoHolesValid
&& poly
->NoHoles
)
276 for (pl
= poly
->NoHoles
; pl
!= NULL
; pl
= pl
->next
)
278 if (clip_box
== NULL
)
279 fill_contour (gc
, pl
);
281 fill_clipped_contour (gc
, pl
, clip_box
);
285 /* Draw other parts of the polygon if fullpoly flag is set */
286 /* NB: No "NoHoles" cache for these */
287 if (TEST_FLAG (FULLPOLYFLAG
, poly
))
289 PolygonType p
= *poly
;
291 for (p
.Clipped
= poly
->Clipped
->f
;
292 p
.Clipped
!= poly
->Clipped
;
293 p
.Clipped
= p
.Clipped
->f
)
294 NoHolesPolygonDicer (&p
, clip_box
, fill_contour_cb
, gc
);
299 thindraw_hole_cb (PLINE
*pl
, void *user_data
)
301 hidGC gc
= (hidGC
)user_data
;
302 thindraw_contour (gc
, pl
);
307 common_thindraw_pcb_polygon (hidGC gc
, PolygonType
*poly
,
308 const BoxType
*clip_box
)
310 thindraw_contour (gc
, poly
->Clipped
->contours
);
311 PolygonHoles (poly
, clip_box
, thindraw_hole_cb
, gc
);
315 common_thindraw_pcb_pad (hidGC gc
, PadType
*pad
, bool clear
, bool mask
)
317 Coord w
= clear
? (mask
? pad
->Mask
318 : pad
->Thickness
+ pad
->Clearance
)
320 Coord x1
, y1
, x2
, y2
;
326 if (x1
> x2
|| y1
> y2
)
330 x1
= x2
; x2
= temp_x
;
331 y1
= y2
; y2
= temp_y
;
333 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
334 gui
->graphics
->set_line_width (gc
, 0);
335 if (TEST_FLAG (SQUAREFLAG
, pad
))
337 /* slanted square pad */
338 double tx
, ty
, theta
;
340 if (x1
== x2
&& y1
== y2
)
343 theta
= atan2 (y2
- y1
, x2
- x1
);
345 /* T is a vector half a thickness long, in the direction of
346 one of the corners. */
347 tx
= t
* cos (theta
+ M_PI
/ 4) * sqrt (2.0);
348 ty
= t
* sin (theta
+ M_PI
/ 4) * sqrt (2.0);
350 gui
->graphics
->draw_line (gc
, x1
- tx
, y1
- ty
, x2
+ ty
, y2
- tx
);
351 gui
->graphics
->draw_line (gc
, x2
+ ty
, y2
- tx
, x2
+ tx
, y2
+ ty
);
352 gui
->graphics
->draw_line (gc
, x2
+ tx
, y2
+ ty
, x1
- ty
, y1
+ tx
);
353 gui
->graphics
->draw_line (gc
, x1
- ty
, y1
+ tx
, x1
- tx
, y1
- ty
);
355 else if (x1
== x2
&& y1
== y2
)
357 gui
->graphics
->draw_arc (gc
, x1
, y1
, t
, t
, 0, 360);
361 /* Slanted round-end pads. */
362 Coord dx
, dy
, ox
, oy
;
367 h
= t
/ sqrt (SQUARE (dx
) + SQUARE (dy
));
368 ox
= dy
* h
+ 0.5 * SGN (dy
);
369 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
371 gui
->graphics
->draw_line (gc
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
373 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
375 Angle angle
= atan2 (dx
, dy
) * 57.295779;
376 gui
->graphics
->draw_line (gc
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
377 gui
->graphics
->draw_arc (gc
, x1
, y1
, t
, t
, angle
- 180, 180);
378 gui
->graphics
->draw_arc (gc
, x2
, y2
, t
, t
, angle
, 180);
384 common_fill_pcb_pad (hidGC gc
, PadType
*pad
, bool clear
, bool mask
)
386 Coord w
= clear
? (mask
? pad
->Mask
387 : pad
->Thickness
+ pad
->Clearance
)
390 if (pad
->Point1
.X
== pad
->Point2
.X
&&
391 pad
->Point1
.Y
== pad
->Point2
.Y
)
393 if (TEST_FLAG (SQUAREFLAG
, pad
))
396 l
= pad
->Point1
.X
- w
/ 2;
397 b
= pad
->Point1
.Y
- w
/ 2;
400 gui
->graphics
->fill_rect (gc
, l
, b
, r
, t
);
404 gui
->graphics
->fill_circle (gc
, pad
->Point1
.X
, pad
->Point1
.Y
, w
/ 2);
409 gui
->graphics
->set_line_cap (gc
, TEST_FLAG (SQUAREFLAG
, pad
) ?
410 Square_Cap
: Round_Cap
);
411 gui
->graphics
->set_line_width (gc
, w
);
413 gui
->graphics
->draw_line (gc
, pad
->Point1
.X
, pad
->Point1
.Y
,
414 pad
->Point2
.X
, pad
->Point2
.Y
);
418 /* ---------------------------------------------------------------------------
420 * x and y are already in display coordinates
421 * the points are numbered:
439 draw_octagon_poly (hidGC gc
, Coord X
, Coord Y
,
440 Coord Thickness
, bool thin_draw
)
442 static FloatPolyType p
[8] = {
443 { 0.5, -TAN_22_5_DEGREE_2
},
444 { TAN_22_5_DEGREE_2
, -0.5 },
445 {-TAN_22_5_DEGREE_2
, -0.5 },
446 {-0.5, -TAN_22_5_DEGREE_2
},
447 {-0.5, TAN_22_5_DEGREE_2
},
448 {-TAN_22_5_DEGREE_2
, 0.5 },
449 { TAN_22_5_DEGREE_2
, 0.5 },
450 { 0.5, TAN_22_5_DEGREE_2
}
452 static int special_size
= 0;
453 static int scaled_x
[8];
454 static int scaled_y
[8];
459 if (Thickness
!= special_size
)
461 special_size
= Thickness
;
462 for (i
= 0; i
< 8; i
++)
464 scaled_x
[i
] = p
[i
].X
* special_size
;
465 scaled_y
[i
] = p
[i
].Y
* special_size
;
468 /* add line offset */
469 for (i
= 0; i
< 8; i
++)
471 polygon_x
[i
] = X
+ scaled_x
[i
];
472 polygon_y
[i
] = Y
+ scaled_y
[i
];
478 gui
->graphics
->set_line_cap (gc
, Round_Cap
);
479 gui
->graphics
->set_line_width (gc
, 0);
480 polygon_x
[8] = X
+ scaled_x
[0];
481 polygon_y
[8] = Y
+ scaled_y
[0];
482 for (i
= 0; i
< 8; i
++)
483 gui
->graphics
->draw_line (gc
, polygon_x
[i
], polygon_y
[i
],
484 polygon_x
[i
+ 1], polygon_y
[i
+ 1]);
487 gui
->graphics
->fill_polygon (gc
, 8, polygon_x
, polygon_y
);
491 common_fill_pcb_pv (hidGC fg_gc
, hidGC bg_gc
, PinType
*pv
, bool drawHole
, bool mask
)
493 Coord w
= mask
? pv
->Mask
: pv
->Thickness
;
496 if (TEST_FLAG (HOLEFLAG
, pv
))
499 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, r
);
502 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, r
);
503 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
504 gui
->graphics
->set_line_width (fg_gc
, 0);
505 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
510 if (TEST_FLAG (SQUAREFLAG
, pv
))
517 gui
->graphics
->fill_rect (fg_gc
, l
, b
, r
, t
);
519 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
520 draw_octagon_poly (fg_gc
, pv
->X
, pv
->Y
, w
, false);
521 else /* draw a round pin or via */
522 gui
->graphics
->fill_circle (fg_gc
, pv
->X
, pv
->Y
, r
);
524 /* and the drilling hole (which is always round) */
526 gui
->graphics
->fill_circle (bg_gc
, pv
->X
, pv
->Y
, pv
->DrillingHole
/ 2);
530 common_thindraw_pcb_pv (hidGC fg_gc
, hidGC bg_gc
, PinType
*pv
, bool drawHole
, bool mask
)
532 Coord w
= mask
? pv
->Mask
: pv
->Thickness
;
535 if (TEST_FLAG (HOLEFLAG
, pv
))
538 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
541 r
= pv
->DrillingHole
/ 2;
542 gui
->graphics
->set_line_cap (bg_gc
, Round_Cap
);
543 gui
->graphics
->set_line_width (bg_gc
, 0);
544 gui
->graphics
->draw_arc (bg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
549 if (TEST_FLAG (SQUAREFLAG
, pv
))
556 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
557 gui
->graphics
->set_line_width (fg_gc
, 0);
558 gui
->graphics
->draw_line (fg_gc
, r
, t
, r
, b
);
559 gui
->graphics
->draw_line (fg_gc
, l
, t
, l
, b
);
560 gui
->graphics
->draw_line (fg_gc
, r
, t
, l
, t
);
561 gui
->graphics
->draw_line (fg_gc
, r
, b
, l
, b
);
564 else if (TEST_FLAG (OCTAGONFLAG
, pv
))
566 draw_octagon_poly (fg_gc
, pv
->X
, pv
->Y
, w
, true);
568 else /* draw a round pin or via */
570 gui
->graphics
->set_line_cap (fg_gc
, Round_Cap
);
571 gui
->graphics
->set_line_width (fg_gc
, 0);
572 gui
->graphics
->draw_arc (fg_gc
, pv
->X
, pv
->Y
, r
, r
, 0, 360);
575 /* and the drilling hole (which is always round */
578 gui
->graphics
->set_line_cap (bg_gc
, Round_Cap
);
579 gui
->graphics
->set_line_width (bg_gc
, 0);
580 gui
->graphics
->draw_arc (bg_gc
, pv
->X
, pv
->Y
, pv
->DrillingHole
/ 2,
581 pv
->DrillingHole
/ 2, 0, 360);
586 common_draw_helpers_init (HID_DRAW
*graphics
)
588 graphics
->draw_pcb_line
= common_draw_pcb_line
;
589 graphics
->draw_pcb_arc
= common_draw_pcb_arc
;
590 graphics
->draw_pcb_text
= common_draw_pcb_text
;
592 graphics
->fill_pcb_polygon
= common_fill_pcb_polygon
;
593 graphics
->thindraw_pcb_polygon
= common_thindraw_pcb_polygon
;
594 graphics
->fill_pcb_pad
= common_fill_pcb_pad
;
595 graphics
->thindraw_pcb_pad
= common_thindraw_pcb_pad
;
596 graphics
->fill_pcb_pv
= common_fill_pcb_pv
;
597 graphics
->thindraw_pcb_pv
= common_thindraw_pcb_pv
;