pcb 4.1.1
An interactive printed circuit board layout editor.

print.c

Go to the documentation of this file.
00001 
00041 #ifdef HAVE_CONFIG_H
00042 #include "config.h"
00043 #endif
00044 
00045 #include "global.h"
00046 #include "hid_draw.h"
00047 
00048 #include <time.h>
00049 #ifdef HAVE_UNISTD_H
00050 #include <unistd.h>
00051 #endif
00052 
00053 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
00054 #include <locale.h>
00055 #endif
00056 
00057 #include "data.h"
00058 #include "draw.h"
00059 #include "drill.h"
00060 #include "file.h"
00061 #include "find.h"
00062 #include "error.h"
00063 #include "misc.h"
00064 #include "print.h"
00065 #include "polygon.h"
00066 #include "rtree.h"
00067 #include "search.h"
00068 
00069 #include "hid.h"
00070 
00071 #ifdef HAVE_LIBDMALLOC
00072 #include <dmalloc.h>
00073 #endif
00074 
00075 /* ---------------------------------------------------------------------------
00076  * prints a FAB drawing.
00077  */
00078 
00079 #define TEXT_SIZE       MIL_TO_COORD(150)
00080 #define TEXT_LINE       MIL_TO_COORD(150)
00081 #define DRILL_MARK_SIZE MIL_TO_COORD(16)
00082 #define FAB_LINE_W      MIL_TO_COORD(8)
00083 
00084 static void
00085 fab_line (hidGC gc, int x1, int y1, int x2, int y2)
00086 {
00087   gui->graphics->draw_line (gc, x1, y1, x2, y2);
00088 }
00089 
00090 static void
00091 fab_circle (hidGC gc, int x, int y, int r)
00092 {
00093   gui->graphics->draw_arc (gc, x, y, r, r, 0, 180);
00094   gui->graphics->draw_arc (gc, x, y, r, r, 180, 180);
00095 }
00096 
00102 static void
00103 text_at (hidGC gc, int x, int y, int align, char *fmt, ...)
00104 {
00105   char tmp[512];
00106   int w = 0, i;
00107   TextType t;
00108   va_list a;
00109   FontType *font = &PCB->Font;
00110   va_start (a, fmt);
00111   vsprintf (tmp, fmt, a);
00112   va_end (a);
00113   t.Direction = 0;
00114   t.TextString = tmp;
00115   t.Scale = COORD_TO_MIL(TEXT_SIZE);  /* pcnt of 100mil base height */
00116   t.Flags = NoFlags ();
00117   t.X = x;
00118   t.Y = y;
00119   for (i = 0; tmp[i]; i++)
00120     w +=
00121       (font->Symbol[(int) tmp[i]].Width + font->Symbol[(int) tmp[i]].Delta);
00122   w = SCALE_TEXT (w, t.Scale);
00123   t.X -= w * (align & 3) / 2;
00124   if (t.X < 0)
00125     t.X = 0;
00126   gui->graphics->draw_pcb_text (gc, &t, 0);
00127   if (align & 8)
00128     fab_line (gc, t.X,
00129               t.Y + SCALE_TEXT (font->MaxHeight, t.Scale) + MIL_TO_COORD(10),
00130               t.X + w,
00131               t.Y + SCALE_TEXT (font->MaxHeight, t.Scale) + MIL_TO_COORD(10));
00132 }
00133 
00139 static void
00140 drill_sym (hidGC gc, int idx, int x, int y)
00141 {
00142   int type = idx % 5;
00143   int size = idx / 5;
00144   int s2 = (size + 1) * DRILL_MARK_SIZE;
00145   int i;
00146   switch (type)
00147     {
00148     case 0:                     /* Y */ ;
00149       fab_line (gc, x, y, x, y + s2);
00150       fab_line (gc, x, y, x + s2 * 13 / 15, y - s2 / 2);
00151       fab_line (gc, x, y, x - s2 * 13 / 15, y - s2 / 2);
00152       for (i = 1; i <= size; i++)
00153         fab_circle (gc, x, y, i * DRILL_MARK_SIZE);
00154       break;
00155     case 1:                     /* + */
00156       ;
00157       fab_line (gc, x, y - s2, x, y + s2);
00158       fab_line (gc, x - s2, y, x + s2, y);
00159       for (i = 1; i <= size; i++)
00160         {
00161           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00162                         x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE);
00163           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00164                         x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00165           fab_line (gc, x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE,
00166                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00167           fab_line (gc, x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00168                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00169         }
00170       break;
00171     case 2:                     /* X */ ;
00172       fab_line (gc, x - s2 * 3 / 4, y - s2 * 3 / 4, x + s2 * 3 / 4,
00173                 y + s2 * 3 / 4);
00174       fab_line (gc, x - s2 * 3 / 4, y + s2 * 3 / 4, x + s2 * 3 / 4,
00175                 y - s2 * 3 / 4);
00176       for (i = 1; i <= size; i++)
00177         {
00178           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00179                         x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE);
00180           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00181                         x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00182           fab_line (gc, x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE,
00183                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00184           fab_line (gc, x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00185                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00186         }
00187       break;
00188     case 3:                     /* circle */ ;
00189       for (i = 0; i <= size; i++)
00190         fab_circle (gc, x, y, (i + 1) * DRILL_MARK_SIZE - DRILL_MARK_SIZE / 2);
00191       break;
00192     case 4:                     /* square */
00193       for (i = 1; i <= size + 1; i++)
00194         {
00195           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00196                         x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE);
00197           fab_line (gc, x - i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00198                         x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00199           fab_line (gc, x - i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE,
00200                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00201           fab_line (gc, x + i * DRILL_MARK_SIZE, y - i * DRILL_MARK_SIZE,
00202                         x + i * DRILL_MARK_SIZE, y + i * DRILL_MARK_SIZE);
00203         }
00204       break;
00205     }
00206 }
00207 
00208 static int
00209 count_drill_lines (DrillInfoType *AllDrills)
00210 {
00211   int n, ds = 0;
00212   for (n = AllDrills->DrillN - 1; n >= 0; n--)
00213     {
00214       DrillType *drill = &(AllDrills->Drill[n]);
00215       if (drill->PinCount + drill->ViaCount > drill->UnplatedCount)
00216         ds++;
00217       if (drill->UnplatedCount)
00218         ds++;
00219     }
00220   return ds;
00221 }
00222 
00223 
00224 int
00225 PrintFab_overhang (void)
00226 {
00227   DrillInfoType *AllDrills = GetDrillInfo (PCB->Data);
00228   int ds = count_drill_lines (AllDrills);
00229   if (ds < 4)
00230     ds = 4;
00231   return (ds + 2) * TEXT_LINE;
00232 }
00233 
00234 void
00235 PrintFab (hidGC gc)
00236 {
00237   DrillInfoType *AllDrills;
00238   int i, n, yoff, total_drills = 0, ds = 0;
00239   time_t currenttime;
00240   const char *utcFmt = "%c UTC";
00241   char utcTime[64];
00242 #ifdef ENABLE_NLS
00243   char *oldlocale;
00244 #endif
00245   AllDrills = GetDrillInfo (PCB->Data);
00246   yoff = -TEXT_LINE;
00247 
00248   /* count how many drill description lines will be needed */
00249   ds = count_drill_lines (AllDrills);
00250 
00251   /*
00252    * When we only have a few drill sizes we need to make sure the
00253    * drill table header doesn't fall on top of the board info
00254    * section.
00255    */
00256   if (ds < 4)
00257     {
00258       yoff -= (4 - ds) * TEXT_LINE;
00259     }
00260 
00261   gui->graphics->set_line_width (gc, FAB_LINE_W);
00262 
00263   for (n = AllDrills->DrillN - 1; n >= 0; n--)
00264     {
00265       int plated_sym = -1, unplated_sym = -1;
00266       DrillType *drill = &(AllDrills->Drill[n]);
00267       if (drill->PinCount + drill->ViaCount > drill->UnplatedCount)
00268         plated_sym = --ds;
00269       if (drill->UnplatedCount)
00270         unplated_sym = --ds;
00271       gui->graphics->set_color (gc, PCB->PinColor);
00272       for (i = 0; i < drill->PinN; i++)
00273         drill_sym (gc, TEST_FLAG (HOLEFLAG, drill->Pin[i]) ?
00274                    unplated_sym : plated_sym, drill->Pin[i]->X,
00275                    drill->Pin[i]->Y);
00276       if (plated_sym != -1)
00277         {
00278           drill_sym (gc, plated_sym, TEXT_SIZE, yoff + TEXT_SIZE / 4);
00279           text_at (gc, MIL_TO_COORD(1350), yoff, MIL_TO_COORD(2), "YES");
00280           text_at (gc, MIL_TO_COORD(980), yoff, MIL_TO_COORD(2), "%d",
00281                    drill->PinCount + drill->ViaCount - drill->UnplatedCount);
00282 
00283           if (unplated_sym != -1)
00284             yoff -= TEXT_LINE;
00285         }
00286       if (unplated_sym != -1)
00287         {
00288           drill_sym (gc, unplated_sym, TEXT_SIZE, yoff + TEXT_SIZE / 4);
00289           text_at (gc, MIL_TO_COORD(1400), yoff, MIL_TO_COORD(2), "NO");
00290           text_at (gc, MIL_TO_COORD(980), yoff, MIL_TO_COORD(2), "%d", drill->UnplatedCount);
00291         }
00292       gui->graphics->set_color (gc, PCB->ElementColor);
00293       text_at (gc, MIL_TO_COORD(450), yoff, MIL_TO_COORD(2), "%0.3f",
00294                COORD_TO_INCH(drill->DrillSize));
00295       if (plated_sym != -1 && unplated_sym != -1)
00296         text_at (gc, MIL_TO_COORD(450), yoff + TEXT_LINE, MIL_TO_COORD(2), "%0.3f",
00297                  COORD_TO_INCH(drill->DrillSize));
00298       yoff -= TEXT_LINE;
00299       total_drills += drill->PinCount;
00300       total_drills += drill->ViaCount;
00301     }
00302 
00303   gui->graphics->set_color (gc, PCB->ElementColor);
00304   text_at (gc, 0, yoff, MIL_TO_COORD(9), "Symbol");
00305   text_at (gc, MIL_TO_COORD(410), yoff, MIL_TO_COORD(9), "Diam. (Inch)");
00306   text_at (gc, MIL_TO_COORD(950), yoff, MIL_TO_COORD(9), "Count");
00307   text_at (gc, MIL_TO_COORD(1300), yoff, MIL_TO_COORD(9), "Plated?");
00308   yoff -= TEXT_LINE;
00309   text_at (gc, 0, yoff, 0,
00310            "There are %d different drill sizes used in this layout, %d holes total",
00311            AllDrills->DrillN, total_drills);
00312   /* Create a portable timestamp. */
00313 #ifdef ENABLE_NLS
00314   oldlocale = setlocale (LC_TIME, "C");
00315 #endif
00316   currenttime = time (NULL);
00317   strftime (utcTime, sizeof utcTime, utcFmt, gmtime (&currenttime));
00318 #ifdef ENABLE_NLS
00319   setlocale (LC_TIME, oldlocale);
00320 #endif
00321 
00322   yoff = -TEXT_LINE;
00323   for (i = 0; i < max_copper_layer; i++)
00324     {
00325       LayerType *l = LAYER_PTR (i);
00326       if (l->Name && (l->LineN || l->ArcN))
00327         {
00328           if (strcmp ("route", l->Name) == 0)
00329             break;
00330           if (strcmp ("outline", l->Name) == 0)
00331             break;
00332         }
00333     }
00334   if (i == max_copper_layer)
00335     {
00336       gui->graphics->set_line_width (gc,  MIL_TO_COORD(10));
00337       gui->graphics->draw_line (gc, 0, 0, PCB->MaxWidth, 0);
00338       gui->graphics->draw_line (gc, 0, 0, 0, PCB->MaxHeight);
00339       gui->graphics->draw_line (gc, PCB->MaxWidth, 0, PCB->MaxWidth,
00340                       PCB->MaxHeight);
00341       gui->graphics->draw_line (gc, 0, PCB->MaxHeight, PCB->MaxWidth,
00342                       PCB->MaxHeight);
00343       /*FPrintOutline (); */
00344       gui->graphics->set_line_width (gc, FAB_LINE_W);
00345       text_at (gc, MIL_TO_COORD(2000), yoff, 0,
00346                "Maximum Dimensions: %f mils wide, %f mils high",
00347                COORD_TO_MIL(PCB->MaxWidth), COORD_TO_MIL(PCB->MaxHeight));
00348       text_at (gc, PCB->MaxWidth / 2, PCB->MaxHeight + MIL_TO_COORD(20), 1,
00349                "Board outline is the centerline of this %f mil"
00350                " rectangle - 0,0 to %f,%f mils",
00351                COORD_TO_MIL(FAB_LINE_W), COORD_TO_MIL(PCB->MaxWidth), COORD_TO_MIL(PCB->MaxHeight));
00352     }
00353   else
00354     {
00355       LayerType *layer = LAYER_PTR (i);
00356       gui->graphics->set_line_width (gc, MIL_TO_COORD(10));
00357       LINE_LOOP (layer);
00358       {
00359         gui->graphics->draw_line (gc, line->Point1.X, line->Point1.Y,
00360                         line->Point2.X, line->Point2.Y);
00361       }
00362       END_LOOP;
00363       ARC_LOOP (layer);
00364       {
00365         gui->graphics->draw_arc (gc, arc->X, arc->Y, arc->Width,
00366                        arc->Height, arc->StartAngle, arc->Delta);
00367       }
00368       END_LOOP;
00369       TEXT_LOOP (layer);
00370       {
00371         gui->graphics->draw_pcb_text (gc, text, 0);
00372       }
00373       END_LOOP;
00374       gui->graphics->set_line_width (gc, FAB_LINE_W);
00375       text_at (gc, PCB->MaxWidth / 2, PCB->MaxHeight + MIL_TO_COORD(20), 1,
00376                "Board outline is the centerline of this path");
00377     }
00378   yoff -= TEXT_LINE;
00379   text_at (gc, MIL_TO_COORD(2000), yoff, 0, "Date: %s", utcTime);
00380   yoff -= TEXT_LINE;
00381   text_at (gc, MIL_TO_COORD(2000), yoff, 0, "Author: %s", pcb_author ());
00382   yoff -= TEXT_LINE;
00383   text_at (gc, MIL_TO_COORD(2000), yoff, 0,
00384            "Title: %s - Fabrication Drawing", UNKNOWN (PCB->Name));
00385 }