pcb 4.1.1
An interactive printed circuit board layout editor.

draw_helpers.c

Go to the documentation of this file.
00001 #include "global.h"
00002 #include "hid.h"
00003 #include "hid_draw.h"
00004 #include "data.h" /* For global "PCB" variable */
00005 #include "rotate.h" /* For RotateLineLowLevel() */
00006 #include "polygon.h"
00007 #include "draw_helpers.h"
00008 
00009 
00010 void
00011 common_draw_pcb_line (hidGC gc, LineType *line)
00012 {
00013   gui->graphics->set_line_cap (gc, Trace_Cap);
00014   if (TEST_FLAG (THINDRAWFLAG, PCB))
00015     gui->graphics->set_line_width (gc, 0);
00016   else
00017     gui->graphics->set_line_width (gc, line->Thickness);
00018 
00019   gui->graphics->draw_line (gc,
00020                             line->Point1.X, line->Point1.Y,
00021                             line->Point2.X, line->Point2.Y);
00022 }
00023 
00024 void
00025 common_draw_pcb_arc (hidGC gc, ArcType *arc)
00026 {
00027   if (!arc->Thickness)
00028     return;
00029 
00030   if (TEST_FLAG (THINDRAWFLAG, PCB))
00031     gui->graphics->set_line_width (gc, 0);
00032   else
00033     gui->graphics->set_line_width (gc, arc->Thickness);
00034   gui->graphics->set_line_cap (gc, Trace_Cap);
00035 
00036   gui->graphics->draw_arc (gc, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta);
00037 }
00038 
00039 /* ---------------------------------------------------------------------------
00040  * drawing routine for text objects
00041  */
00042 static void
00043 common_draw_pcb_text (hidGC gc, TextType *Text, Coord min_line_width)
00044 {
00045   Coord x = 0;
00046   unsigned char *string = (unsigned char *) Text->TextString;
00047   Cardinal n;
00048   FontType *font = &PCB->Font;
00049 
00050   while (string && *string)
00051     {
00052       /* draw lines if symbol is valid and data is present */
00053       if (*string <= MAX_FONTPOSITION && font->Symbol[*string].Valid)
00054         {
00055           LineType *line = font->Symbol[*string].Line;
00056           LineType newline;
00057 
00058           for (n = font->Symbol[*string].LineN; n; n--, line++)
00059             {
00060               /* create one line, scale, move, rotate and swap it */
00061               newline = *line;
00062               newline.Point1.X = SCALE_TEXT (newline.Point1.X + x, Text->Scale);
00063               newline.Point1.Y = SCALE_TEXT (newline.Point1.Y, Text->Scale);
00064               newline.Point2.X = SCALE_TEXT (newline.Point2.X + x, Text->Scale);
00065               newline.Point2.Y = SCALE_TEXT (newline.Point2.Y, Text->Scale);
00066               newline.Thickness = SCALE_TEXT (newline.Thickness, Text->Scale / 2);
00067               if (newline.Thickness < min_line_width)
00068                 newline.Thickness = min_line_width;
00069 
00070               RotateLineLowLevel (&newline, 0, 0, Text->Direction);
00071 
00072               /* the labels of SMD objects on the bottom
00073                * side haven't been swapped yet, only their offset
00074                */
00075               if (TEST_FLAG (ONSOLDERFLAG, Text))
00076                 {
00077                   newline.Point1.X = SWAP_SIGN_X (newline.Point1.X);
00078                   newline.Point1.Y = SWAP_SIGN_Y (newline.Point1.Y);
00079                   newline.Point2.X = SWAP_SIGN_X (newline.Point2.X);
00080                   newline.Point2.Y = SWAP_SIGN_Y (newline.Point2.Y);
00081                 }
00082               /* add offset and draw line */
00083               newline.Point1.X += Text->X;
00084               newline.Point1.Y += Text->Y;
00085               newline.Point2.X += Text->X;
00086               newline.Point2.Y += Text->Y;
00087               gui->graphics->draw_pcb_line (gc, &newline);
00088             }
00089 
00090           /* move on to next cursor position */
00091           x += (font->Symbol[*string].Width + font->Symbol[*string].Delta);
00092         }
00093       else
00094         {
00095           /* the default symbol is a filled box */
00096           BoxType defaultsymbol = PCB->Font.DefaultSymbol;
00097           Coord size = (defaultsymbol.X2 - defaultsymbol.X1) * 6 / 5;
00098 
00099           defaultsymbol.X1 = SCALE_TEXT (defaultsymbol.X1 + x, Text->Scale);
00100           defaultsymbol.Y1 = SCALE_TEXT (defaultsymbol.Y1, Text->Scale);
00101           defaultsymbol.X2 = SCALE_TEXT (defaultsymbol.X2 + x, Text->Scale);
00102           defaultsymbol.Y2 = SCALE_TEXT (defaultsymbol.Y2, Text->Scale);
00103 
00104           RotateBoxLowLevel (&defaultsymbol, 0, 0, Text->Direction);
00105 
00106           /* add offset and draw box */
00107           defaultsymbol.X1 += Text->X;
00108           defaultsymbol.Y1 += Text->Y;
00109           defaultsymbol.X2 += Text->X;
00110           defaultsymbol.Y2 += Text->Y;
00111           gui->graphics->fill_rect (gc,
00112                                     defaultsymbol.X1, defaultsymbol.Y1,
00113                                     defaultsymbol.X2, defaultsymbol.Y2);
00114 
00115           /* move on to next cursor position */
00116           x += size;
00117         }
00118       string++;
00119     }
00120 }
00121 
00122 static void
00123 fill_contour (hidGC gc, PLINE *pl)
00124 {
00125   Coord *x, *y, n, i = 0;
00126   VNODE *v;
00127 
00128   n = pl->Count;
00129   x = (Coord *)malloc (n * sizeof (*x));
00130   y = (Coord *)malloc (n * sizeof (*y));
00131 
00132   for (v = &pl->head; i < n; v = v->next)
00133     {
00134       x[i] = v->point[0];
00135       y[i++] = v->point[1];
00136     }
00137 
00138   gui->graphics->fill_polygon (gc, n, x, y);
00139 
00140   free (x);
00141   free (y);
00142 }
00143 
00144 static void
00145 thindraw_contour (hidGC gc, PLINE *pl)
00146 {
00147   VNODE *v;
00148   Coord last_x, last_y;
00149   Coord this_x, this_y;
00150 
00151   gui->graphics->set_line_width (gc, 0);
00152   gui->graphics->set_line_cap (gc, Round_Cap);
00153 
00154   /* If the contour is round, use an arc drawing routine. */
00155   if (pl->is_round)
00156     {
00157       gui->graphics->draw_arc (gc, pl->cx, pl->cy, pl->radius, pl->radius, 0, 360);
00158       return;
00159     }
00160 
00161   /* Need at least two points in the contour */
00162   if (pl->head.next == NULL)
00163     return;
00164 
00165   last_x = pl->head.point[0];
00166   last_y = pl->head.point[1];
00167   v = pl->head.next;
00168 
00169   do
00170     {
00171       this_x = v->point[0];
00172       this_y = v->point[1];
00173 
00174       gui->graphics->draw_line (gc, last_x, last_y, this_x, this_y);
00175       // gui->graphics->fill_circle (gc, this_x, this_y, 30);
00176 
00177       last_x = this_x;
00178       last_y = this_y;
00179     }
00180   while ((v = v->next) != pl->head.next);
00181 }
00182 
00183 static void
00184 fill_contour_cb (PLINE *pl, void *user_data)
00185 {
00186   hidGC gc = (hidGC)user_data;
00187   PLINE *local_pl = pl;
00188 
00189   fill_contour (gc, pl);
00190   poly_FreeContours (&local_pl);
00191 }
00192 
00193 static void
00194 fill_clipped_contour (hidGC gc, PLINE *pl, const BoxType *clip_box)
00195 {
00196   PLINE *pl_copy;
00197   POLYAREA *clip_poly;
00198   POLYAREA *piece_poly;
00199   POLYAREA *clipped_pieces;
00200   POLYAREA *draw_piece;
00201   int x;
00202 
00203   clip_poly = RectPoly (clip_box->X1, clip_box->X2,
00204                         clip_box->Y1, clip_box->Y2);
00205   poly_CopyContour (&pl_copy, pl);
00206   piece_poly = poly_Create ();
00207   poly_InclContour (piece_poly, pl_copy);
00208   x = poly_Boolean_free (piece_poly, clip_poly,
00209                          &clipped_pieces, PBO_ISECT);
00210   if (x != err_ok || clipped_pieces == NULL)
00211     return;
00212 
00213   draw_piece = clipped_pieces;
00214   do
00215     {
00216       /* NB: The polygon won't have any holes in it */
00217       fill_contour (gc, draw_piece->contours);
00218     }
00219   while ((draw_piece = draw_piece->f) != clipped_pieces);
00220   poly_Free (&clipped_pieces);
00221 }
00222 
00223 /* If at least 50% of the bounding box of the polygon is on the screen,
00224  * lets compute the complete no-holes polygon.
00225  */
00226 #define BOUNDS_INSIDE_CLIP_THRESHOLD 0.5
00227 static int
00228 should_compute_no_holes (PolygonType *poly, const BoxType *clip_box)
00229 {
00230   Coord x1, x2, y1, y2;
00231   double poly_bounding_area;
00232   double clipped_poly_area;
00233 
00234   /* If there is no passed clip box, compute the whole thing */
00235   if (clip_box == NULL)
00236     return 1;
00237 
00238   x1 = MAX (poly->BoundingBox.X1, clip_box->X1);
00239   x2 = MIN (poly->BoundingBox.X2, clip_box->X2);
00240   y1 = MAX (poly->BoundingBox.Y1, clip_box->Y1);
00241   y2 = MIN (poly->BoundingBox.Y2, clip_box->Y2);
00242 
00243   /* Check if the polygon is outside the clip box */
00244   if ((x2 <= x1) || (y2 <= y1))
00245     return 0;
00246 
00247   poly_bounding_area = (double)(poly->BoundingBox.X2 - poly->BoundingBox.X1) *
00248                        (double)(poly->BoundingBox.Y2 - poly->BoundingBox.Y1);
00249 
00250   clipped_poly_area = (double)(x2 - x1) * (double)(y2 - y1);
00251 
00252   if (clipped_poly_area / poly_bounding_area >= BOUNDS_INSIDE_CLIP_THRESHOLD)
00253     return 1;
00254 
00255   return 0;
00256 }
00257 #undef BOUNDS_INSIDE_CLIP_THRESHOLD
00258 
00259 void
00260 common_gui_draw_pcb_polygon (hidGC gc, PolygonType *polygon, const BoxType *clip_box)
00261 {
00262   if (polygon->Clipped == NULL)
00263     return;
00264 
00265   if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
00266     gui->graphics->thindraw_pcb_polygon (gc, polygon, clip_box);
00267   else
00268     gui->graphics->fill_pcb_polygon (gc, polygon, clip_box);
00269 
00270   /* If checking planes, thin-draw any pieces which have been clipped away */
00271   if (TEST_FLAG (CHECKPLANESFLAG, PCB) && !TEST_FLAG (FULLPOLYFLAG, polygon))
00272     {
00273       PolygonType poly = *polygon;
00274 
00275       for (poly.Clipped = polygon->Clipped->f;
00276            poly.Clipped != polygon->Clipped;
00277            poly.Clipped = poly.Clipped->f)
00278         gui->graphics->thindraw_pcb_polygon (gc, &poly, clip_box);
00279     }
00280 }
00281 
00282 void
00283 common_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
00284 {
00285   if (poly->Clipped == NULL)
00286     return;
00287 
00288   if (!poly->NoHolesValid)
00289     {
00290       /* If enough of the polygon is on-screen, compute the entire
00291        * NoHoles version and cache it for later rendering, otherwise
00292        * just compute what we need to render now.
00293        */
00294       if (should_compute_no_holes (poly, clip_box))
00295         ComputeNoHoles (poly);
00296       else
00297         NoHolesPolygonDicer (poly, clip_box, fill_contour_cb, gc);
00298     }
00299   if (poly->NoHolesValid && poly->NoHoles)
00300     {
00301       PLINE *pl;
00302 
00303       for (pl = poly->NoHoles; pl != NULL; pl = pl->next)
00304         {
00305           if (clip_box == NULL)
00306             fill_contour (gc, pl);
00307           else
00308             fill_clipped_contour (gc, pl, clip_box);
00309         }
00310     }
00311 
00312   /* Draw other parts of the polygon if fullpoly flag is set */
00313   /* NB: No "NoHoles" cache for these */
00314   if (TEST_FLAG (FULLPOLYFLAG, poly))
00315     {
00316       PolygonType p = *poly;
00317 
00318       for (p.Clipped = poly->Clipped->f;
00319            p.Clipped != poly->Clipped;
00320            p.Clipped = p.Clipped->f)
00321         NoHolesPolygonDicer (&p, clip_box, fill_contour_cb, gc);
00322     }
00323 }
00324 
00325 static int
00326 thindraw_hole_cb (PLINE *pl, void *user_data)
00327 {
00328   hidGC gc = (hidGC)user_data;
00329   thindraw_contour (gc, pl);
00330   return 0;
00331 }
00332 
00333 void
00334 common_thindraw_pcb_polygon (hidGC gc, PolygonType *poly,
00335                              const BoxType *clip_box)
00336 {
00337   if (poly->Clipped == NULL)
00338     return;
00339 
00340   thindraw_contour (gc, poly->Clipped->contours);
00341   PolygonHoles (poly, clip_box, thindraw_hole_cb, gc);
00342 
00343   /* Draw other parts of the polygon if fullpoly flag is set */
00344   if (TEST_FLAG (FULLPOLYFLAG, poly))
00345     {
00346       PolygonType p = *poly;
00347 
00348       for (p.Clipped = poly->Clipped->f;
00349            p.Clipped != poly->Clipped;
00350            p.Clipped = p.Clipped->f)
00351         {
00352           thindraw_contour (gc, p.Clipped->contours);
00353           PolygonHoles (&p, clip_box, thindraw_hole_cb, gc);
00354         }
00355     }
00356 }
00357 
00358 void
00359 common_thindraw_pcb_pad (hidGC gc, PadType *pad, bool clear, bool mask)
00360 {
00361   Coord w = clear ? (mask ? pad->Mask
00362                           : pad->Thickness + pad->Clearance)
00363                   : pad->Thickness;
00364   Coord x1, y1, x2, y2;
00365   Coord t = w / 2;
00366   x1 = pad->Point1.X;
00367   y1 = pad->Point1.Y;
00368   x2 = pad->Point2.X;
00369   y2 = pad->Point2.Y;
00370   if (x1 > x2 || y1 > y2)
00371     {
00372       Coord temp_x = x1;
00373       Coord temp_y = y1;
00374       x1 = x2; x2 = temp_x;
00375       y1 = y2; y2 = temp_y;
00376     }
00377   gui->graphics->set_line_cap (gc, Round_Cap);
00378   gui->graphics->set_line_width (gc, 0);
00379   if (TEST_FLAG (SQUAREFLAG, pad))
00380     {
00381       /* slanted square pad */
00382       double tx, ty, theta;
00383 
00384       if (x1 == x2 && y1 == y2)
00385         theta = 0;
00386       else
00387         theta = atan2 (y2 - y1, x2 - x1);
00388 
00389       /* T is a vector half a thickness long, in the direction of
00390          one of the corners.  */
00391       tx = t * cos (theta + M_PI / 4) * sqrt (2.0);
00392       ty = t * sin (theta + M_PI / 4) * sqrt (2.0);
00393 
00394       gui->graphics->draw_line (gc, x1 - tx, y1 - ty, x2 + ty, y2 - tx);
00395       gui->graphics->draw_line (gc, x2 + ty, y2 - tx, x2 + tx, y2 + ty);
00396       gui->graphics->draw_line (gc, x2 + tx, y2 + ty, x1 - ty, y1 + tx);
00397       gui->graphics->draw_line (gc, x1 - ty, y1 + tx, x1 - tx, y1 - ty);
00398     }
00399   else if (x1 == x2 && y1 == y2)
00400     {
00401       gui->graphics->draw_arc (gc, x1, y1, t, t, 0, 360);
00402     }
00403   else
00404     {
00405       /* Slanted round-end pads.  */
00406       Coord dx, dy, ox, oy;
00407       double h;
00408 
00409       dx = x2 - x1;
00410       dy = y2 - y1;
00411       h = t / hypot (dx, dy);
00412       ox = dy * h + 0.5 * SGN (dy);
00413       oy = -(dx * h + 0.5 * SGN (dx));
00414 
00415       gui->graphics->draw_line (gc, x1 + ox, y1 + oy, x2 + ox, y2 + oy);
00416 
00417       if (abs (ox) >= pixel_slop || abs (oy) >= pixel_slop)
00418         {
00419           Angle angle = atan2 (dx, dy) * 57.295779;
00420           gui->graphics->draw_line (gc, x1 - ox, y1 - oy, x2 - ox, y2 - oy);
00421           gui->graphics->draw_arc (gc, x1, y1, t, t, angle - 180, 180);
00422           gui->graphics->draw_arc (gc, x2, y2, t, t, angle, 180);
00423         }
00424     }
00425 }
00426 
00427 /* Computes the coordinates of the corners of a squared pad.  */
00428 static void
00429 common_get_pad_polygon(Coord x[4], Coord y[4], const PadType *l, int w)
00430 {
00431   Coord dX, dY;
00432   double dwx, dwy;
00433   Coord x1, y1, x2, y2;
00434   x1 = l->Point1.X;
00435   y1 = l->Point1.Y;
00436   x2 = l->Point2.X;
00437   y2 = l->Point2.Y;
00438   if (x1 > x2 || y1 > y2)
00439     {
00440       Coord temp_x = x1;
00441       Coord temp_y = y1;
00442       x1 = x2; x2 = temp_x;
00443       y1 = y2; y2 = temp_y;
00444     }
00445 
00446   dX = x2 - x1;
00447   dY = y2 - y1;
00448 
00449   if (dY == 0)
00450     {
00451       dwx = w / 2;
00452       dwy = 0;
00453     }
00454   else if (dX == 0)
00455     {
00456       dwx = 0;
00457       dwy = w / 2;
00458     }
00459   else
00460     {
00461       double r;
00462 
00463       r = hypot (dX, dY) * 2;
00464       dwx = w / r * dX;
00465       dwy =  w / r * dY;
00466     }
00467 
00468   x[0] = x1 - dwx + dwy;
00469   y[0] = y1 - dwy - dwx;
00470 
00471   x[1] = x1 - dwx - dwy;
00472   y[1] = y1 - dwy + dwx;
00473 
00474   x[2] = x2 + dwx - dwy;
00475   y[2] = y2 + dwy + dwx;
00476 
00477   x[3] = x2 + dwx + dwy;
00478   y[3] = y2 + dwy - dwx;
00479 }
00480 
00481 void
00482 common_fill_pcb_pad (hidGC gc, PadType *pad, bool clear, bool mask)
00483 {
00484   Coord w = clear ? (mask ? pad->Mask
00485                           : pad->Thickness + pad->Clearance)
00486                   : pad->Thickness;
00487 
00488   if (pad->Point1.X == pad->Point2.X &&
00489       pad->Point1.Y == pad->Point2.Y)
00490     {
00491       if (TEST_FLAG (SQUAREFLAG, pad))
00492         {
00493           Coord l, r, t, b;
00494           l = pad->Point1.X - w / 2;
00495           b = pad->Point1.Y - w / 2;
00496           r = l + w;
00497           t = b + w;
00498           gui->graphics->fill_rect (gc, l, b, r, t);
00499         }
00500       else
00501         {
00502           gui->graphics->fill_circle (gc, pad->Point1.X, pad->Point1.Y, w / 2);
00503         }
00504     }
00505   else
00506     {
00507       gui->graphics->set_line_cap (gc, TEST_FLAG (SQUAREFLAG, pad) ?
00508                                Square_Cap : Round_Cap);
00509       gui->graphics->set_line_width (gc, w);
00510 
00511       if (TEST_FLAG (SQUAREFLAG, pad))
00512         {
00513           Coord x[4], y[4];
00514           common_get_pad_polygon (x, y, pad, w);
00515           gui->graphics->fill_polygon (gc, 4, x, y);
00516         }
00517       else
00518         gui->graphics->draw_line (gc, pad->Point1.X, pad->Point1.Y,
00519                                   pad->Point2.X, pad->Point2.Y);
00520     }
00521 }
00522 
00523 /* ---------------------------------------------------------------------------
00524  * draws one polygon
00525  * x and y are already in display coordinates
00526  * the points are numbered:
00527  *
00528  *          5 --- 6
00529  *         /       \
00530  *        4         7
00531  *        |         |
00532  *        3         0
00533  *         \       /
00534  *          2 --- 1
00535  */
00536 
00537 typedef struct
00538 {
00539   double X, Y;
00540 }
00541 FloatPolyType;
00542 
00543 static void
00544 draw_octagon_poly (hidGC gc, Coord X, Coord Y,
00545                    Coord Thickness, bool thin_draw)
00546 {
00547   static FloatPolyType p[8] = {
00548     { 0.5,               -TAN_22_5_DEGREE_2},
00549     { TAN_22_5_DEGREE_2, -0.5              },
00550     {-TAN_22_5_DEGREE_2, -0.5              },
00551     {-0.5,               -TAN_22_5_DEGREE_2},
00552     {-0.5,                TAN_22_5_DEGREE_2},
00553     {-TAN_22_5_DEGREE_2,  0.5              },
00554     { TAN_22_5_DEGREE_2,  0.5              },
00555     { 0.5,                TAN_22_5_DEGREE_2}
00556   };
00557   static int special_size = 0;
00558   static int scaled_x[8];
00559   static int scaled_y[8];
00560   Coord polygon_x[9];
00561   Coord polygon_y[9];
00562   int i;
00563 
00564   if (Thickness != special_size)
00565     {
00566       special_size = Thickness;
00567       for (i = 0; i < 8; i++)
00568         {
00569           scaled_x[i] = p[i].X * special_size;
00570           scaled_y[i] = p[i].Y * special_size;
00571         }
00572     }
00573   /* add line offset */
00574   for (i = 0; i < 8; i++)
00575     {
00576       polygon_x[i] = X + scaled_x[i];
00577       polygon_y[i] = Y + scaled_y[i];
00578     }
00579 
00580   if (thin_draw)
00581     {
00582       int i;
00583       gui->graphics->set_line_cap (gc, Round_Cap);
00584       gui->graphics->set_line_width (gc, 0);
00585       polygon_x[8] = X + scaled_x[0];
00586       polygon_y[8] = Y + scaled_y[0];
00587       for (i = 0; i < 8; i++)
00588         gui->graphics->draw_line (gc, polygon_x[i    ], polygon_y[i    ],
00589                             polygon_x[i + 1], polygon_y[i + 1]);
00590     }
00591   else
00592     gui->graphics->fill_polygon (gc, 8, polygon_x, polygon_y);
00593 }
00594 
00595 void
00596 common_fill_pcb_pv (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask)
00597 {
00598   Coord w = mask ? pv->Mask : pv->Thickness;
00599   Coord r = w / 2;
00600 
00601   if (TEST_FLAG (HOLEFLAG, pv))
00602     {
00603       if (mask)
00604         gui->graphics->fill_circle (bg_gc, pv->X, pv->Y, r);
00605       if (drawHole)
00606         {
00607           gui->graphics->fill_circle (bg_gc, pv->X, pv->Y, r);
00608           gui->graphics->set_line_cap (fg_gc, Round_Cap);
00609           gui->graphics->set_line_width (fg_gc, 0);
00610           gui->graphics->draw_arc (fg_gc, pv->X, pv->Y, r, r, 0, 360);
00611         }
00612       return;
00613     }
00614 
00615   if (TEST_FLAG (SQUAREFLAG, pv))
00616     {
00617       Coord l = pv->X - r;
00618       Coord b = pv->Y - r;
00619       Coord r = l + w;
00620       Coord t = b + w;
00621 
00622       gui->graphics->fill_rect (fg_gc, l, b, r, t);
00623     }
00624   else if (TEST_FLAG (OCTAGONFLAG, pv))
00625     draw_octagon_poly (fg_gc, pv->X, pv->Y, w, false);
00626   else /* draw a round pin or via */
00627     gui->graphics->fill_circle (fg_gc, pv->X, pv->Y, r);
00628 
00629   /* and the drilling hole  (which is always round) */
00630   if (drawHole)
00631     gui->graphics->fill_circle (bg_gc, pv->X, pv->Y, pv->DrillingHole / 2);
00632 }
00633 
00634 void
00635 common_thindraw_pcb_pv (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask)
00636 {
00637   Coord w = mask ? pv->Mask : pv->Thickness;
00638   Coord r = w / 2;
00639 
00640   if (TEST_FLAG (HOLEFLAG, pv))
00641     {
00642       if (mask)
00643         gui->graphics->draw_arc (fg_gc, pv->X, pv->Y, r, r, 0, 360);
00644       if (drawHole)
00645         {
00646           r = pv->DrillingHole / 2;
00647           gui->graphics->set_line_cap (bg_gc, Round_Cap);
00648           gui->graphics->set_line_width (bg_gc, 0);
00649           gui->graphics->draw_arc (bg_gc, pv->X, pv->Y, r, r, 0, 360);
00650         }
00651       return;
00652     }
00653 
00654   if (TEST_FLAG (SQUAREFLAG, pv))
00655     {
00656       Coord l = pv->X - r;
00657       Coord b = pv->Y - r;
00658       Coord r = l + w;
00659       Coord t = b + w;
00660 
00661       gui->graphics->set_line_cap (fg_gc, Round_Cap);
00662       gui->graphics->set_line_width (fg_gc, 0);
00663       gui->graphics->draw_line (fg_gc, r, t, r, b);
00664       gui->graphics->draw_line (fg_gc, l, t, l, b);
00665       gui->graphics->draw_line (fg_gc, r, t, l, t);
00666       gui->graphics->draw_line (fg_gc, r, b, l, b);
00667 
00668     }
00669   else if (TEST_FLAG (OCTAGONFLAG, pv))
00670     {
00671       draw_octagon_poly (fg_gc, pv->X, pv->Y, w, true);
00672     }
00673   else /* draw a round pin or via */
00674     {
00675       gui->graphics->set_line_cap (fg_gc, Round_Cap);
00676       gui->graphics->set_line_width (fg_gc, 0);
00677       gui->graphics->draw_arc (fg_gc, pv->X, pv->Y, r, r, 0, 360);
00678     }
00679 
00680   /* and the drilling hole  (which is always round */
00681   if (drawHole)
00682     {
00683       gui->graphics->set_line_cap (bg_gc, Round_Cap);
00684       gui->graphics->set_line_width (bg_gc, 0);
00685       gui->graphics->draw_arc (bg_gc, pv->X, pv->Y, pv->DrillingHole / 2,
00686                      pv->DrillingHole / 2, 0, 360);
00687     }
00688 }
00689 
00690 void
00691 common_draw_helpers_init (HID_DRAW *graphics)
00692 {
00693   graphics->draw_pcb_line        = common_draw_pcb_line;
00694   graphics->draw_pcb_arc         = common_draw_pcb_arc;
00695   graphics->draw_pcb_text        = common_draw_pcb_text;
00696   graphics->draw_pcb_polygon     = common_fill_pcb_polygon; /* Default is the non-GUI case */
00697 
00698   graphics->fill_pcb_polygon     = common_fill_pcb_polygon;
00699   graphics->thindraw_pcb_polygon = common_thindraw_pcb_polygon;
00700   graphics->fill_pcb_pad         = common_fill_pcb_pad;
00701   graphics->thindraw_pcb_pad     = common_thindraw_pcb_pad;
00702   graphics->fill_pcb_pv          = common_fill_pcb_pv;
00703   graphics->thindraw_pcb_pv      = common_thindraw_pcb_pv;
00704 }