pcb 4.1.1
An interactive printed circuit board layout editor.

gsvit.c

Go to the documentation of this file.
00001 
00051 #ifdef HAVE_CONFIG_H
00052 #include "config.h"
00053 #endif
00054 
00055 #include <stdio.h>
00056 #include <stdarg.h>
00057 #include <stdlib.h>
00058 #include <string.h>
00059 #include <assert.h>
00060 
00061 #include <time.h>
00062 
00063 #include "global.h"
00064 #include "error.h" /* Message() */
00065 #include "data.h"
00066 #include "misc.h"
00067 #include "rats.h"
00068 #include "find.h"
00069 
00070 #include "hid.h"
00071 #include "hid_draw.h"
00072 #include "../hidint.h"
00073 #include "hid/common/hidnogui.h"
00074 #include "hid/common/draw_helpers.h"
00075 
00076 #include <gd.h>
00077 #include "xmlout.h"
00078 
00079 #include "hid/common/hidinit.h"
00080 #include "pcb-printf.h"
00081 
00082 #ifdef HAVE_LIBDMALLOC
00083 #include <dmalloc.h>
00084 #endif
00085 
00086 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
00087 #define MAXREFPINS 32 /* max length of following list */
00088 static char *reference_pin_names[] = {"1", "2", "A1", "A2", "B1", "B2", 0};
00089 
00090 /* Needed for PNG export */
00091 
00092 struct color_struct {
00093   /* the descriptor used by the gd library */
00094   int c;
00095   /* so I can figure out what rgb value c refers to */
00096   unsigned int r, g, b;
00097 };
00098 
00099 struct hid_gc_struct {
00100   HID *me_pointer;
00101   EndCapStyle cap;
00102   Coord width;
00103   unsigned char r, g, b;
00104   int erase;
00105   struct color_struct *color;
00106   gdImagePtr brush;
00107 };
00108 
00109 struct gsvit_net_layer {
00110   GList *Line;
00111   GList *Arc; 
00112   GList *Polygon;
00113 };
00114 
00115 struct gsvit_netlist {
00116   char* name;
00117   GList *Pin;
00118   GList *Via;
00119   GList *Pad;
00120   struct gsvit_net_layer layer[MAX_LAYER];
00121   struct color_struct color;
00122   int colorIndex;
00123 };
00124 
00125 
00129 struct drill_hole
00130 {
00131   int cx;
00132   int cy;
00133   int is_plated;
00134 }; 
00135 
00139 struct single_size_drills
00140 {
00141   double diameter_inches;
00142   Coord radius;
00143   int n_holes;
00144   int n_holes_allocated;   
00145   struct drill_hole* holes;
00146 };
00147 static struct single_size_drills* drills = NULL;
00148 
00149 typedef struct _StringList
00150 {
00151   char *str;
00152   struct _StringList *next;
00153 } StringList;
00154 
00155 typedef struct _BomList
00156 {
00157   char *descr;
00158   char *value;
00159   int num;
00160   StringList *refdes;
00161   struct _BomList *next;
00162 } BomList;
00163 
00164 static int n_drills = 0; 
00166 static int n_drills_allocated = 0;
00167 
00168 static int save_drill = 0;
00169 
00170 static int is_plated = 0;        
00171 
00172 struct gsvit_netlist* gsvit_netlist = NULL;
00173 
00174 int hashColor = gdBrushed;
00175 
00176 static struct color_struct* color_array[0x100];
00177 
00178 static HID gsvit_hid;
00179 
00180 static HID_DRAW gsvit_graphics;
00181 
00182 static struct color_struct *black = NULL, *white = NULL;
00183 
00184 static Coord linewidth = -1;
00185 
00186 static gdImagePtr lastbrush = (gdImagePtr)((void *) -1);
00187 
00191 static gdImagePtr gsvit_im = NULL;
00192 
00196 static FILE *gsvit_f = NULL;
00197 
00198 static int is_mask;
00199 
00200 static int is_drill;
00201 
00207 static int gsvit_export_group[MAX_GROUP];
00208 
00212 static int gsvit_cur_group;
00213 
00217 static const char *gsvit_basename = NULL;
00218 
00222 static int gsvit_dpi = -1;
00223 
00224 HID_Attribute   gsvit_attribute_list[] = {
00225 /* other HIDs expect this to be first.  */
00226 
00227 /* %start-doc options "96 gsvit Options"
00228 @ftable @code
00229 @item -- basename <string>
00230 File name prefix.
00231 @end ftable
00232 %end-doc
00233 */
00234   {"basename", "File name prefix",
00235    HID_String, 0, 0, {0, 0, 0}, 0, 0},
00236 #define HA_basename 0
00237 
00238 /* %start-doc options "96 gsvit Options"
00239 @ftable @code
00240 @item --dpi <num>
00241 Horizontal scale factor (grid points/inch).
00242 @end ftable
00243 %end-doc
00244 */
00245   {"dpi", "Horizontal scale factor (grid points/inch)",
00246    HID_Integer, 0, 1000, {1000, 0, 0}, 0, 0}, /* 1000 --> 1 mil (25.4 um) resolution */
00247 #define HA_dpi 1
00248 
00249 };
00250 
00251 #define NUM_OPTIONS (sizeof (gsvit_attribute_list) / sizeof (gsvit_attribute_list[0]))
00252 
00253 REGISTER_ATTRIBUTES(gsvit_attribute_list)
00254         static HID_Attr_Val gsvit_values[NUM_OPTIONS];
00255 
00256 void gsvit_create_netlist (void);
00257 void gsvit_destroy_netlist (void);
00258 static void gsvit_xml_out (char* gsvit_basename);
00259 static void gsvit_build_net_from_selected (struct gsvit_netlist* currNet);
00260 static void gsvit_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
00261 static void gsvit_write_xnets (void);
00262 
00263 
00282 char *
00283 hslToRgb (int h, uint8_t s, uint8_t l)
00284 {
00285   static char rgb[3];
00286   float H = fmod ((float)(h), 360.0);
00287   float S = s;
00288   float L = l;
00289 
00290   int sect;
00291   float C, X;
00292   float m;
00293   float Rp, Gp, Bp;
00294 
00295   L /= 255.0;
00296   S /= 255.0;
00297   sect = h / 60;
00298 
00299   C = (1.0 - fabs (2 * L - 1.0)) * S;
00300   X = C * (1.0 - fabs (fmod ((H / 60.0), 2.0)  - 1.0));
00301   m = L - C / 2.0;
00302 
00303   switch (sect)
00304   {
00305     case 0:
00306       Rp = C;
00307       Gp = X;
00308       Bp = 0.0;
00309       break;
00310     case 1:
00311       Rp = X;
00312       Gp = C;
00313       Bp = 0.0;
00314       break;
00315     case 2:
00316       Rp = 0.0;
00317       Gp = C;
00318       Bp = X;
00319       break;
00320     case 3:
00321       Rp = 0.0;
00322       Gp = X;
00323       Bp = C;
00324       break;
00325     case 4:
00326       Rp = X;
00327       Gp = 0.0;
00328       Bp = C;
00329       break;
00330     case 5:
00331       Rp = C;
00332       Gp = 0.0;
00333       Bp = X;
00334       break;
00335     default:
00336       Rp = 0.0;
00337       Gp = 0.0;
00338       Bp = 0.0;
00339       break;
00340   }
00341 
00342   rgb[0] = (Rp + m) * 0xFF;
00343   rgb[1] = (Gp + m) * 0xFF;
00344   rgb[2] = (Bp + m) * 0xFF;
00345 
00346   return (rgb);
00347 }
00348 
00349 
00350 void
00351 gsvit_build_net_from_selected (struct gsvit_netlist* currNet)
00352 {
00353   COPPERLINE_LOOP (PCB->Data);
00354   {
00355     if (TEST_FLAG (SELECTEDFLAG, line))
00356     {
00357       currNet->layer[l].Line = g_list_prepend(currNet->layer[l].Line, line);
00358     }
00359   }
00360   ENDALL_LOOP;
00361 
00362   COPPERARC_LOOP (PCB->Data);
00363   {
00364     if (TEST_FLAG (SELECTEDFLAG, arc))
00365     {
00366       currNet->layer[l].Arc = g_list_prepend (currNet->layer[l].Arc, arc);
00367     }
00368   }
00369   ENDALL_LOOP;
00370 
00371   COPPERPOLYGON_LOOP (PCB->Data);
00372   {
00373     if (TEST_FLAG (SELECTEDFLAG, polygon))
00374     {
00375       currNet->layer[l].Polygon = g_list_prepend (currNet->layer[l].Polygon, polygon);
00376     }
00377   }
00378   ENDALL_LOOP;
00379 
00380   ALLPAD_LOOP (PCB->Data);
00381   {
00382     if (TEST_FLAG (SELECTEDFLAG, pad))
00383     {
00384       currNet->Pad = g_list_prepend (currNet->Pad, pad);
00385     }
00386   }
00387   ENDALL_LOOP;
00388 
00389   ALLPIN_LOOP (PCB->Data);
00390   {
00391     if (TEST_FLAG (SELECTEDFLAG, pin))
00392     {
00393       currNet->Pin = g_list_prepend (currNet->Pin, pin);
00394     }
00395   }
00396   ENDALL_LOOP;
00397 
00398   VIA_LOOP (PCB->Data);
00399   {
00400     if (TEST_FLAG (SELECTEDFLAG, via))
00401     {
00402       currNet->Via = g_list_prepend(currNet->Via, via);
00403     }
00404   }
00405   END_LOOP;
00406 }
00407 
00408 
00409 void
00410 gsvit_create_netlist (void)
00411 {
00412   int i;
00413   int numNets = PCB->NetlistLib.MenuN;
00414   gsvit_netlist = (struct gsvit_netlist*) malloc (sizeof (struct gsvit_netlist) * numNets);
00415   memset (gsvit_netlist, 0, sizeof (struct gsvit_netlist) * numNets);
00416 
00417   for (i = 0; i < numNets; i++)
00418   { /* For each net in the netlist. */
00419     int j;
00420     LibraryEntryType* entry;
00421     ConnectionType conn;
00422 
00423     struct gsvit_netlist* currNet = &gsvit_netlist[i];
00424     currNet->name = PCB->NetlistLib.Menu[i].Name + 2;
00427     InitConnectionLookup ();
00428     ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
00429     for (j = PCB->NetlistLib.Menu[i].EntryN, entry = PCB->NetlistLib.Menu[i].Entry; j; j--, entry++)
00430     { /* For each component (pin/pad) in the net. */
00431       if (SeekPad(entry, &conn, false))
00432       {
00433         RatFindHook(conn.type, conn.ptr1, conn.ptr2, conn.ptr2, false, SELECTEDFLAG, false);
00434       }
00435     }
00436     /* The conn should now contain a list of all elements that are part
00437      * of the net.
00438      * Now build a database of all things selected as part of this net.
00439      */
00440     gsvit_build_net_from_selected (currNet);
00441 
00442     ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG);
00443     FreeConnectionLookupMemory ();
00444   }
00445 
00446   /* Assign colors to nets. */
00447   for (i = 0; i < numNets; i++)
00448   {
00449     char *rgb = NULL;
00450     char name[0x100];
00451     int j;
00452     int phase = (360 * i) / numNets;
00453 
00454     for (j = 0; gsvit_netlist[i].name[j]; j++)
00455     {
00456       name[j] = tolower (gsvit_netlist[i].name[j]);
00457     }
00458 
00459     name[j] = 0; 
00461     if (strstr (name, "gnd") || strstr (name, "ground"))
00462     { /* Make gnd nets darker. */
00463       rgb = hslToRgb (phase, (70 * 256) / 100, (20 * 256) / 100);
00464     }
00465     else if (strstr (name, "unnamed"))
00466     {/* Make unnamed nets grayer. */
00467       rgb = hslToRgb (phase, (15 * 256) / 100, (40 * 256) / 100);
00468     }
00469     else
00470       rgb = hslToRgb (phase, (70 * 256) / 100, (50 * 256) / 100);
00471 
00472     gsvit_netlist[i].color.r = rgb[0];
00473     gsvit_netlist[i].color.g = rgb[1];
00474     gsvit_netlist[i].color.b = rgb[2];
00475   }
00476 }
00477 
00478 
00479 void
00480 gsvit_destroy_netlist (void)
00481 {
00482   int i;
00483   for (i = 0; i < PCB->NetlistLib.MenuN; i++)
00484   { /* For each net in the netlist. */
00485     struct gsvit_netlist* currNet = &gsvit_netlist[i];
00486     int j;
00487     for (j = 0; j < MAX_LAYER; j++)
00488     {
00489       g_list_free (currNet->layer[j].Line);
00490       g_list_free (currNet->layer[j].Arc);
00491       g_list_free (currNet->layer[j].Polygon);
00492     }
00493     g_list_free (currNet->Pad);
00494     g_list_free (currNet->Pin);
00495     g_list_free (currNet->Via);
00496   }
00497   free (gsvit_netlist);
00498 }
00499 
00500 
00504 static int
00505 pcb_to_gsvit (Coord pcb)
00506 {
00507   return COORD_TO_INCH (pcb) * gsvit_dpi;
00508 }
00509 
00510 
00511 static char *
00512 gsvit_get_png_name (const char *basename, const char *suffix)
00513 {
00514   char *buf;
00515   int len;
00516 
00517   len = strlen (basename) + strlen(suffix) + 6;
00518   buf = (char *) malloc (sizeof (*buf) * len);
00519 
00520   sprintf (buf, "%s.%s.png", basename, suffix);
00521 
00522   return buf;
00523 }
00524 
00525 
00526 static void
00527 gsvit_write_xspace (void)
00528 {
00529   double xh;
00530   uint32_t h;
00531   uint32_t w;
00532   char buff[0x100];
00533   int i, idx;
00534   const char *ext;
00535   char *src;
00536 
00537   xh = (1000.0* 2.54e-2) / ((double) gsvit_dpi); /* Units are in mm. */
00538   h = (uint32_t) pcb_to_gsvit (PCB->MaxHeight); /* Units are in counts. */
00539   w = (uint32_t) pcb_to_gsvit (PCB->MaxWidth);
00540 
00541   sprintf (buff, "%f", xh);
00542   XOUT_ELEMENT_START ("space");
00543   XOUT_INDENT ();
00544   XOUT_NEWLINE ();
00545   XOUT_ELEMENT ("comment", "***** Space *****");
00546   XOUT_NEWLINE ();
00547 
00548   XOUT_ELEMENT_ATTR ("resolution", "units", "mm", buff);
00549   XOUT_NEWLINE ();
00550 
00551   sprintf (buff, "%d", w);
00552   XOUT_ELEMENT ("width", buff);
00553   XOUT_NEWLINE ();
00554   sprintf (buff, "%d", h);
00555   XOUT_ELEMENT ("height", buff);
00556   XOUT_NEWLINE ();
00557   XOUT_ELEMENT_START ("layers");
00558   XOUT_INDENT ();
00559   for (i = 0; i < MAX_GROUP; i++)
00560     if (gsvit_export_group[i]) {
00561       idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
00562       ext = layer_type_to_file_name (idx, FNS_fixed);
00563       src = gsvit_get_png_name (gsvit_basename, ext);
00564       XOUT_NEWLINE ();
00565       XOUT_ELEMENT_ATTR ("layer", "name", ext, src);
00566     }
00567   XOUT_DETENT ();
00568   XOUT_NEWLINE ();
00569   XOUT_ELEMENT_END ("layers");
00570   XOUT_DETENT ();
00571   XOUT_NEWLINE ();
00572   XOUT_ELEMENT_END ("space");
00573   XOUT_DETENT ();
00574 }
00575 
00576 
00577 static void
00578 gsvit_write_xnets (void)
00579 {
00580   LibraryType netlist;
00581   LibraryMenuType *net;
00582   LibraryEntryType *pin;
00583   int n, m, i, idx;
00584 
00585   netlist = PCB->NetlistLib;
00586 
00587   XOUT_INDENT ();
00588   XOUT_NEWLINE ();
00589   XOUT_ELEMENT_START ("nets");
00590   XOUT_INDENT ();
00591   XOUT_NEWLINE ();
00592   XOUT_ELEMENT ("comment", "***** Nets *****");
00593   XOUT_NEWLINE ();
00594 
00595   for (n = 0; n < netlist.MenuN; n++) {
00596     char buff[0x100];
00597     net = &netlist.Menu[n];
00598 
00599     /* Weird, but correct */
00600     XOUT_ELEMENT_ATTR_START ("net", "name", &net->Name[2]);
00601 //    snprintf(buff, 0x100, "%d,%d,%d", net->color.r, net->color.g, net->color.b);
00602 //    XOUT_ELEMENT_2ATTR_START("net", "name", &net->Name[2], "color", buff );
00603 
00604     for (m = 0; m < net->EntryN; m++) {
00605       pin = &net->Entry[m];
00606 
00607       /* pin_name_to_xy(pin, &x, &y); */
00608 
00609       for (i = 0; i < MAX_GROUP; i++)
00610         if (gsvit_export_group[i]) {
00611           idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
00612           layer_type_to_file_name (idx, FNS_fixed);
00613 
00614           if (m != 0 || i != 0)
00615             XOUT_ELEMENT_DATA (", ");
00616           snprintf (buff, 0x100, "%s", pin->ListEntry);
00617           {
00618             char* src = buff;
00619             while (*src)
00620             {
00621               if (*src == '-')
00622                 *src = '.';
00623               src++;
00624             }
00625           }
00626 
00627           XOUT_ELEMENT_DATA (buff);
00628           break;
00629         }
00630     }
00631 
00632     XOUT_ELEMENT_END ("net");
00633     if (n+1 >= netlist.MenuN)
00634       XOUT_DETENT ();
00635     XOUT_NEWLINE ();
00636   }
00637   XOUT_ELEMENT_END ("nets");
00638   XOUT_DETENT ();
00639 }
00640 
00641 
00642 static StringList *
00643 string_insert (char *str, StringList *list)
00644 {
00645   StringList *newlist, *cur;
00646 
00647   if ((newlist = (StringList *) malloc (sizeof (StringList))) == NULL)
00648   {
00649     fprintf (stderr, "malloc() failed in string_insert()\n");
00650     exit (1);
00651   }
00652 
00653   newlist->next = NULL;
00654   newlist->str = strdup (str);
00655 
00656   if (list == NULL)
00657     return (newlist);
00658 
00659   cur = list;
00660   while (cur->next != NULL)
00661     cur = cur->next;
00662 
00663   cur->next = newlist;
00664 
00665   return (list);
00666 }
00667 
00668 
00669 static BomList *
00670 bom_insert (char *refdes, char *descr, char *value, BomList * bom)
00671 {
00672   BomList *newlist, *cur, *prev = NULL;
00673 
00674   if (bom == NULL)
00675   {
00676     /* this is the first element so automatically create an entry */
00677     if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL)
00678     {
00679       fprintf (stderr, "malloc() failed in bom_insert()\n");
00680       exit (1);
00681     }
00682 
00683     newlist->next = NULL;
00684     newlist->descr = strdup (descr);
00685     newlist->value = strdup (value);
00686     newlist->num = 1;
00687     newlist->refdes = string_insert (refdes, NULL);
00688     return (newlist);
00689   }
00690 
00691   /* search and see if we already have used one of these
00692   components */
00693   cur = bom;
00694   while (cur != NULL)
00695   {
00696     if ((NSTRCMP (descr, cur->descr) == 0) && (NSTRCMP (value, cur->value) == 0))
00697     {
00698       cur->num++;
00699       cur->refdes = string_insert (refdes, cur->refdes);
00700       break;
00701     }
00702     prev = cur;
00703     cur = cur->next;
00704   }
00705 
00706   if (cur == NULL)
00707   {
00708     if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL)
00709     {
00710       fprintf (stderr, "malloc() failed in bom_insert()\n");
00711       exit (1);
00712     }
00713 
00714     prev->next = newlist;
00715 
00716     newlist->next = NULL;
00717     newlist->descr = strdup (descr);
00718     newlist->value = strdup (value);
00719     newlist->num = 1;
00720     newlist->refdes = string_insert (refdes, NULL);
00721   }
00722   return (bom);
00723 }
00724 
00725 
00726 static double
00727 xyToAngle (double x, double y, bool morethan2pins)
00728 {
00729   double d = atan2 (-y, x) * 180.0 / M_PI;
00730 
00731   /* IPC 7351 defines different rules for 2 pin elements */
00732   if (morethan2pins)
00733   {
00734     /* Multi pin case:
00735     * Output 0 degrees if pin1 in is top left or top, i.e. between angles of
00736     * 80 to 170 degrees.
00737     * Pin #1 can be at dead top (e.g. certain PLCCs) or anywhere in the top
00738     * left.
00739     */
00740     if (d < -100)
00741       return 90; /* -180 to -100 */
00742     else if (d < -10)
00743       return 180; /* -100 to -10 */
00744     else if (d < 80)
00745       return 270; /* -10 to 80 */
00746     else if (d < 170)
00747       return 0; /* 80 to 170 */
00748     else
00749       return 90; /* 170 to 180 */
00750   }
00751   else
00752   {
00753     /* 2 pin element:
00754     * Output 0 degrees if pin #1 is in top left or left, i.e. in sector
00755     * between angles of 95 and 185 degrees.
00756     */
00757     if (d < -175)
00758       return 0; /* -180 to -175 */
00759     else if (d < -85)
00760       return 90; /* -175 to -85 */
00761     else if (d < 5)
00762       return 180; /* -85 to 5 */
00763     else if (d < 95)
00764       return 270; /* 5 to 95 */
00765     else
00766       return 0; /* 95 to 180 */
00767   }
00768 }
00769 
00770 
00774 static void 
00775 gsvit_parse_arguments (int *argc, char ***argv)
00776 {
00777   hid_register_attributes (gsvit_attribute_list, sizeof (gsvit_attribute_list) /
00778     sizeof (gsvit_attribute_list[0]));
00779 
00780   hid_parse_command_line(argc, argv);
00781 }
00782 
00783 
00784 static HID_Attribute *
00785 gsvit_get_export_options (int *n)
00786 {
00787   static char *last_made_filename = 0;
00788 
00789   if (PCB) {
00790     derive_default_filename (PCB->Filename, &gsvit_attribute_list[HA_basename],
00791       ".gsvit", &last_made_filename);
00792   }
00793 
00794   if (n) {
00795     *n = NUM_OPTIONS;
00796   }
00797 
00798   return gsvit_attribute_list;
00799 }
00800 
00801 
00802 static char* CleanXBOMString (char *in)
00803 {
00804   char *out;
00805 //  int i;
00806   char* src;
00807   char* dest;
00808 
00809   if ((out = (char *)malloc ((strlen (in) + 1+0x40) * sizeof (char))) == NULL)
00810   {
00811     fprintf (stderr, "Error:  CleanBOMString() malloc() failed\n");
00812     exit (1);
00813   }
00814   dest = out;
00815   src = in;
00816   while(*src != '\0')
00817   {
00818     switch (*src)
00819     {
00820     case '<':
00821       *dest++ = '&';
00822       *dest++ = 'l';
00823       *dest++ = 't';
00824       *dest = ';';
00825     break;
00826     case '&':
00827       *dest++ = '&';
00828       *dest++ = 'a';
00829       *dest++ = 'm';
00830       *dest++ = 'p';
00831       *dest = ';';
00832     break;
00833     default:
00834       *dest = *src;
00835     }
00836     src++;
00837     dest++;
00838   }
00839   return out;
00840 }
00841 
00842 
00843 static void gsvit_write_xdrills (void)
00844 {
00845   int i = 0;
00846   int j;
00847   char buff[0x100];
00848 
00849   XOUT_NEWLINE ();
00850   XOUT_ELEMENT_START ("drills");
00851   XOUT_INDENT ();
00852   XOUT_NEWLINE ();
00853   XOUT_ELEMENT ("comment", "***** Drills *****");
00854   for (i  = 0; i < n_drills; i++)
00855   {
00856     snprintf (buff, 0x100, "D%d", i);
00857     XOUT_NEWLINE ();
00858     XOUT_ELEMENT_ATTR_START ("drill", "id", buff);
00859     XOUT_INDENT ();
00860     snprintf (buff, 0x100, "%g", drills[i].diameter_inches);
00861     XOUT_NEWLINE ();
00862     XOUT_ELEMENT ("dia_inches", buff);
00863     snprintf (buff, 0x100, "%d", pcb_to_gsvit(drills[i].radius));
00864     XOUT_NEWLINE ();
00865     XOUT_ELEMENT ("radius", buff);
00866     for (j = 0; j < drills[i].n_holes; j++)
00867     {
00868       snprintf (buff, 0x100, "%d,%d", drills[i].holes[j].cx, drills[i].holes[j].cy);
00869       XOUT_NEWLINE ();
00870       if (drills[i].holes[j].is_plated)
00871       {
00872         XOUT_ELEMENT_ATTR_START ("pos", "type", "plated");
00873       }
00874       else
00875       {
00876         XOUT_ELEMENT_ATTR_START ("pos", "type", "unplated");
00877       }
00878       XOUT_ELEMENT_DATA (buff);
00879       XOUT_ELEMENT_END ("pos");
00880     }
00881     XOUT_DETENT ();
00882     XOUT_NEWLINE ();
00883     XOUT_ELEMENT_END ("drill");
00884   }
00885 //      if (drills[i].diameter_inches >= diameter_inches)
00886 //        break;
00887   XOUT_DETENT ();
00888   XOUT_NEWLINE ();
00889   XOUT_ELEMENT_END ("drills");
00890   XOUT_DETENT ();
00891   XOUT_NEWLINE ();
00892 }
00893 
00894 
00895 static void gsvit_write_xcentroids (void)
00896 {
00897   char buff[0x100];
00898 
00899   Coord x, y;
00900   double theta = 0.0;
00901   double sumx, sumy;
00902   int pinfound[MAXREFPINS];
00903   double pinx[MAXREFPINS];
00904   double piny[MAXREFPINS];
00905   double pinangle[MAXREFPINS];
00906   double padcentrex, padcentrey;
00907   double centroidx, centroidy;
00908   double pin1x, pin1y;
00909   int pin_cnt;
00910   int found_any_not_at_centroid;
00911   int found_any;
00912   BomList *bom = NULL;
00913   char *name, *descr, *value,*fixed_rotation;
00914   int rpindex;
00915 
00916   XOUT_INDENT ();
00917   XOUT_NEWLINE ();
00918 
00919   XOUT_ELEMENT_START ("centroids");
00920   XOUT_INDENT ();
00921   XOUT_NEWLINE ();
00922   XOUT_ELEMENT ("comment", "***** Centroids *****");
00923 
00924   /*
00925   * For each element we calculate the centroid of the footprint.
00926   * In addition, we need to extract some notion of rotation.
00927   * While here generate the BOM list
00928   */
00929   ELEMENT_LOOP (PCB->Data);
00930   {
00931 
00932     /* Initialize our pin count and our totals for finding the centroid. */
00933     pin_cnt = 0;
00934     sumx = 0.0;
00935     sumy = 0.0;
00936     for (rpindex = 0; rpindex < MAXREFPINS; rpindex++)
00937       pinfound[rpindex] = 0;
00938 
00939     /* Insert this component into the bill of materials list. */
00940     bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)),
00941                       (char *)UNKNOWN (DESCRIPTION_NAME (element)),
00942                       (char *)UNKNOWN (VALUE_NAME (element)), bom);
00943 
00944 
00945     /*
00946      * Iterate over the pins and pads keeping a running count of how
00947      * many pins/pads total and the sum of x and y coordinates
00948      *
00949      * While we're at it, store the location of pin/pad #1 and #2 if
00950      * we can find them.
00951      */
00952 
00953     PIN_LOOP (element);
00954     {
00955       sumx += (double) pin->X;
00956       sumy += (double) pin->Y;
00957       pin_cnt++;
00958 
00959       for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) {
00960         if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0){
00961           pinx[rpindex] = (double) pin->X;
00962           piny[rpindex] = (double) pin->Y;
00963           pinangle[rpindex] = 0.0; /* pins have no notion of angle */
00964           pinfound[rpindex] = 1;
00965         }
00966       }
00967     }
00968     END_LOOP;
00969 
00970     PAD_LOOP (element);
00971     {
00972       sumx += (pad->Point1.X + pad->Point2.X) / 2.0;
00973       sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0;
00974       pin_cnt++;
00975 
00976       for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) {
00977         if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0) {
00978           padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
00979           padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
00980           pinx[rpindex] = padcentrex;
00981           piny[rpindex] = padcentrey;
00982           /*
00983            * NOTE: We swap the Y points because in PCB, the Y-axis
00984            * is inverted.  Increasing Y moves down.  We want to deal
00985            * in the usual increasing Y moves up coordinates though.
00986            */
00987           pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
00988           pad->Point2.X - pad->Point1.X);
00989           pinfound[rpindex]=1;
00990         }
00991       }
00992     }
00993     END_LOOP;
00994 
00995     if (pin_cnt > 0) {
00996       centroidx = sumx / (double) pin_cnt;
00997       centroidy = sumy / (double) pin_cnt;
00998 
00999       if (NSTRCMP (AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 ) {
01000         x = element->MarkX;
01001         y = element->MarkY;
01002       }
01003       else {
01004         x = centroidx;
01005         y = centroidy;
01006       }
01007 
01008       fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation");
01009       if (fixed_rotation) {
01010         /* The user specified a fixed rotation */
01011         theta = atof (fixed_rotation);
01012         found_any_not_at_centroid = 1;
01013         found_any = 1;
01014       }
01015       else {
01016         /* Find first reference pin not at the  centroid  */
01017         found_any_not_at_centroid = 0;
01018         found_any = 0;
01019         theta = 0.0;
01020         for (rpindex = 0;
01021              reference_pin_names[rpindex] && !found_any_not_at_centroid;
01022              rpindex++) {
01023           if (pinfound[rpindex]) {
01024             found_any = 1;
01025 
01026             /* Recenter pin "#1" onto the axis which cross at the part
01027              * centroid. */
01028             pin1x = pinx[rpindex] - x;
01029             pin1y = piny[rpindex] - y;
01030 
01031             /* flip x, to reverse rotation for elements on back. */
01032             if (FRONT (element) != 1)
01033               pin1x = -pin1x;
01034 
01035             /* if only 1 pin, use pin 1's angle */
01036             if (pin_cnt == 1) {
01037               theta = pinangle[rpindex];
01038               found_any_not_at_centroid = 1;
01039             }
01040             else if ((pin1x != 0.0) || (pin1y != 0.0)) {
01041               theta = xyToAngle (pin1x, pin1y, pin_cnt > 2);
01042               found_any_not_at_centroid = 1;
01043             }
01044           }
01045         }
01046 
01047         if (!found_any) {
01048           Message
01049             ("PrintBOM(): unable to figure out angle because I could\n"
01050              "     not find a suitable reference pin of element %s\n"
01051              "     Setting to %g degrees\n",
01052              UNKNOWN (NAMEONPCB_NAME (element)), theta);
01053         }
01054         else if (!found_any_not_at_centroid) {
01055           Message
01056             ("PrintBOM(): unable to figure out angle of element\n"
01057              "     %s because the reference pin(s) are at the centroid of the part.\n"
01058              "     Setting to %g degrees\n",
01059              UNKNOWN (NAMEONPCB_NAME (element)), theta);
01060         }
01061       }
01062       name = CleanXBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element)));
01063       descr = CleanXBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element)));
01064       value = CleanXBOMString ((char *)UNKNOWN (VALUE_NAME (element)));
01065 
01066       y = PCB->MaxHeight - y;
01067       XOUT_NEWLINE ();
01068       XOUT_ELEMENT_ATTR_START ("xy", "name", name);
01069       XOUT_INDENT ();
01070       XOUT_NEWLINE ();
01071       XOUT_ELEMENT ("description", descr);
01072       XOUT_NEWLINE ();
01073       XOUT_ELEMENT ("value", value);
01074       XOUT_NEWLINE ();
01075       snprintf (buff, 0x100,  "%d,%d", pcb_to_gsvit(x), pcb_to_gsvit(y));
01076       XOUT_ELEMENT ("pos", buff);
01077       XOUT_NEWLINE ();
01078       pcb_snprintf (buff, 0x100, "%g", theta);
01079       XOUT_ELEMENT ("rotation", buff);
01080       XOUT_NEWLINE ();
01081       XOUT_ELEMENT ("side", FRONT (element) == 1 ? "top" : "bottom");
01082       XOUT_DETENT ();
01083       XOUT_NEWLINE ();
01084       XOUT_ELEMENT_END ("xy");
01085 
01086       free (name);
01087       free (descr);
01088       free (value);
01089     }
01090   }
01091   END_LOOP;
01092 
01093   XOUT_DETENT ();
01094   XOUT_NEWLINE ();
01095   XOUT_ELEMENT_END ("centroids");
01096 }
01097 
01098 
01102 void 
01103 gsvit_choose_groups ()
01104 {
01105   int n, m;
01106   LayerType *layer;
01107 
01108   /* Set entire array to 0 (don't export any layer groups by default */
01109   memset (gsvit_export_group, 0, sizeof (gsvit_export_group));
01110 
01111   for (n = 0; n < max_copper_layer; n++) {
01112     layer = &PCB->Data->Layer[n];
01113 
01114     if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN) {
01115       /* Layer isn't empty. */
01120       if (SL_TYPE(n) == 0) {
01121         /* Layer is a copper layer. */
01122         m = GetLayerGroupNumberByNumber (n);
01123 
01124         /* The export layer. */
01125         gsvit_export_group[m] = 1;
01126       }
01127     }
01128   }
01129 }
01130 
01131 
01138 static void 
01139 gsvit_alloc_colors ()
01140 {
01141   int i;
01142   int numNets = PCB->NetlistLib.MenuN;
01143   char *rgb;
01144 
01145   white = (struct color_struct *) malloc (sizeof (*white));
01146   white->r = white->g = white->b = 255;
01147   white->c = gdImageColorAllocate (gsvit_im, white->r, white->g, white->b);
01148 
01149   black = (struct color_struct *) malloc (sizeof (*black));
01150   black->r = black->g = black->b = 0;
01151   black->c = gdImageColorAllocate (gsvit_im, black->r, black->g, black->b);
01152 
01153   for (i = 0; i < numNets; i++) {
01154     gsvit_netlist[i].colorIndex = i;
01155     color_array[i] =  malloc (sizeof (*white));
01156     color_array[i]->r = gsvit_netlist[i].color.r;
01157     color_array[i]->g = gsvit_netlist[i].color.g;
01158     color_array[i]->b = gsvit_netlist[i].color.b;
01159 
01160     color_array[i]->c = gdImageColorAllocate (gsvit_im, color_array[i]->r,  color_array[i]->g,  color_array[i]->b);
01161   }
01162 
01163   color_array[i] =  malloc (sizeof (*white));
01164   rgb = hslToRgb (128, (20 * 256) / 100, (20 * 256) / 100);
01165 
01166   color_array[i]->r = rgb[0];
01167   color_array[i]->g = rgb[1];
01168   color_array[i]->b = rgb[2];
01169   color_array[i]->c = gdImageColorAllocate (gsvit_im, color_array[i]->r, color_array[i]->g, color_array[i]->b);
01170 
01171   printf ("%d colors allocated\n", numNets);
01172 }
01173 
01174 
01175 static void 
01176 gsvit_start_png (const char *basename, const char *suffix)
01177 {
01178   int h, w;
01179   char *buf;
01180 
01181   buf = gsvit_get_png_name (basename, suffix);
01182 
01183   h = pcb_to_gsvit (PCB->MaxHeight);
01184   w = pcb_to_gsvit (PCB->MaxWidth);
01185 
01186   /* gsvit only works with true color images. */
01187   gsvit_im = gdImageCreate (w, h);
01188   gsvit_f = fopen (buf, "wb");
01189 
01190   gsvit_alloc_colors ();
01191 
01192   free (buf);
01193 }
01194 
01195 
01196 static void 
01197 gsvit_finish_png ()
01198 {
01199   int i;
01200 #ifdef HAVE_GDIMAGEPNG
01201   gdImagePng (gsvit_im, gsvit_f);
01202 #else
01203   Message ("gsvit: PNG not supported by gd. Can't write layer mask.\n");
01204 #endif
01205   gdImageDestroy (gsvit_im);
01206   fclose (gsvit_f);
01207 
01208   for (i = 0; i < 0x100; i++) {
01209     free (color_array[i]);
01210   }
01211 
01212   gsvit_im = NULL;
01213   gsvit_f = NULL;
01214 }
01215 
01216 
01217 void 
01218 gsvit_start_png_export ()
01219 {
01220   BoxType region;
01221 
01222   region.X1 = 0;
01223   region.Y1 = 0;
01224   region.X2 = PCB->MaxWidth;
01225   region.Y2 = PCB->MaxHeight;
01226 
01227   linewidth = -1;
01228   lastbrush = (gdImagePtr)((void *) -1);
01229 
01230   hid_expose_callback (&gsvit_hid, &region, 0);
01231 }
01232 
01233 
01234 static void 
01235 gsvit_do_export (HID_Attr_Val *options)
01236 {
01237   int save_ons[MAX_ALL_LAYER];
01238   int i, idx;
01239   char *buf;
01240   int len;
01241 
01242 
01243   if (!options) {
01244     gsvit_get_export_options(0);
01245 
01246     for (i = 0; i < NUM_OPTIONS; i++) {
01247       gsvit_values[i] = gsvit_attribute_list[i].default_val;
01248     }
01249 
01250     options = gsvit_values;
01251   }
01252 
01253   gsvit_basename = options[HA_basename].str_value;
01254 
01255   if (!gsvit_basename) {
01256     gsvit_basename = "pcb-out";
01257   }
01258 
01259   gsvit_dpi = options[HA_dpi].int_value;
01260 
01261   if (gsvit_dpi < 0) {
01262     fprintf (stderr, "ERROR:  dpi may not be < 0\n");
01263     return;
01264   }
01265 
01266   gsvit_create_netlist ();
01267   gsvit_choose_groups ();
01268 
01269   for (i = 0; i < MAX_GROUP; i++) {
01270     if (gsvit_export_group[i]) {
01271       gsvit_cur_group = i;
01272       /* Magic. */
01273       idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
01274       save_drill = (GetLayerGroupNumberByNumber (idx) == GetLayerGroupNumberBySide (BOTTOM_SIDE)) ? 1 : 0;
01275       /* save drills for one layer only */
01276       gsvit_start_png (gsvit_basename, layer_type_to_file_name (idx, FNS_fixed));
01277       hid_save_and_show_layer_ons (save_ons);
01278       gsvit_start_png_export ();
01279       hid_restore_layer_ons (save_ons);
01280       gsvit_finish_png ();
01281     }
01282   }
01283 
01284   len = strlen (gsvit_basename) + 4;
01285   buf = (char *) malloc (sizeof (*buf) * len);
01286 
01287   gsvit_xml_out ((char*) gsvit_basename);
01288   gsvit_destroy_netlist ();
01289 }
01290 
01291 
01292 void
01293 gsvit_xml_out (char *gsvit_basename)
01294 {
01295   char *buf;
01296   int len;
01297   time_t t;
01298 
01299   len = strlen (gsvit_basename) + 4;
01300   buf = (char *) malloc (sizeof (*buf) * len);
01301 
01302   sprintf (buf, "%s.xem", gsvit_basename);
01303   XOUT_INIT (buf);
01304   free (buf);
01305 
01306   XOUT_HEADER ();
01307   XOUT_NEWLINE ();
01308   XOUT_ELEMENT_START ("gsvit");
01309   XOUT_INDENT ();
01310   XOUT_NEWLINE ();
01311   XOUT_ELEMENT ("comment", "Made with PCB gsvit export HID");
01312   XOUT_NEWLINE ();
01313   {
01314     char buff[0x100];
01315     char* src = buff;
01316     t = time (NULL);
01317     strncpy (buff, ctime(&t), 0x100);
01318     while (*src)
01319     {
01320       if ((*src =='\r') || (*src =='\n')) {
01321         *src = 0;
01322         break;
01323       }
01324       src++;
01325     }
01326     XOUT_ELEMENT ("genTime", buff);
01327     XOUT_NEWLINE ();
01328   }
01329   gsvit_write_xspace ();
01330   gsvit_write_xnets ();
01331   gsvit_write_xcentroids();
01332   gsvit_write_xdrills();
01333 
01334   XOUT_ELEMENT_END ("gsvit");
01335   XOUT_NEWLINE ();
01336   XOUT_CLOSE ();
01337 }
01338 
01339 /* *** PNG export (slightly modified code from PNG export HID) ************* */
01340 
01341 static int 
01342 gsvit_set_layer (const char *name, int group, int empty)
01343 {
01344   int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group;
01345 
01346   if (name == 0) {
01347     name = PCB->Data->Layer[idx].Name;
01348   }
01349 
01350   if (strcmp(name, "invisible") == 0) {
01351     return 0;
01352   }
01353 
01354   is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL);
01355   is_mask = (SL_TYPE (idx) == SL_MASK);
01356 
01357   if (is_mask) {
01358     /* Don't print masks. */
01359     return 0;
01360   }
01361 
01362   if (is_drill) {
01363     if (SL_TYPE(idx) == SL_PDRILL)
01364       is_plated =1;
01365     else if (SL_TYPE(idx) == SL_UDRILL)
01366       is_plated =0;
01367 
01368     /* Print 'holes', so that we can fill gaps in the copper layer. */
01369     return 1;
01370   }
01371 
01372   if (group == gsvit_cur_group) {
01373     return 1;
01374   }
01375 
01376   return 0;
01377 }
01378 
01379 
01380 static hidGC 
01381 gsvit_make_gc (void)
01382 {
01383   hidGC rv = (hidGC) malloc (sizeof (struct hid_gc_struct));
01384   rv->me_pointer = &gsvit_hid;
01385   rv->cap = Trace_Cap;
01386   rv->width = 1;
01387   rv->color = (struct color_struct *) malloc (sizeof (*rv->color));
01388   rv->color->r = rv->color->g = rv->color->b = 0;
01389   rv->color->c = 0;
01390   return rv;
01391 }
01392 
01393 
01394 static void 
01395 gsvit_destroy_gc (hidGC gc)
01396 {
01397   free (gc);
01398 }
01399 
01400 
01401 static void 
01402 gsvit_use_mask (enum mask_mode mode)
01403 {
01404   /* Do nothing. */
01405 }
01406 
01407 
01408 static void 
01409 gsvit_set_color (hidGC gc, const char *name)
01410 {
01411   if (gsvit_im == NULL) {
01412     return;
01413   }
01414 
01415   if (name == NULL) {
01416     name = "#ff0000";
01417   }
01418 
01419   if (!strcmp(name, "drill")) {
01420     gc->color = black;
01421     gc->erase = 0;
01422     return;
01423   }
01424 
01425   if (!strcmp(name, "erase")) {
01427     gc->color = white;
01428     gc->erase = 1;
01429     return;
01430   }
01431 
01432   gc->color = black;
01433   gc->erase = 0;
01434   return;
01435 }
01436 
01437 
01438 static void
01439 gsvit_set_line_cap (hidGC gc, EndCapStyle style)
01440 {
01441   gc->cap = style;
01442 }
01443 
01444 
01445 static void
01446 gsvit_set_line_width (hidGC gc, Coord width)
01447 {
01448   gc->width = width;
01449 }
01450 
01451 
01452 static void
01453 gsvit_set_draw_xor (hidGC gc, int xor_)
01454 {
01455  /* Do nothing. */
01456 }
01457 
01458 
01459 static void
01460 gsvit_set_draw_faded (hidGC gc, int faded)
01461 {
01462   /* Do nothing. */
01463 }
01464 
01465 
01466 static void
01467 use_gc (hidGC gc)
01468 {
01469   int need_brush = 0;
01470 
01471   if (gc->me_pointer != &gsvit_hid) {
01472     fprintf (stderr, "Fatal: GC from another HID passed to gsvit HID\n");
01473     abort ();
01474   }
01475 
01476   if (hashColor != gdBrushed) {
01477     need_brush = 1;
01478   }
01479 
01480   if (linewidth != gc->width) {
01481     /* Make sure the scaling doesn't erase lines completely */
01482 /*
01483     if (SCALE (gc->width) == 0 && gc->width > 0)
01484       gdImageSetThickness (im, 1);
01485     else
01486  */
01487     gdImageSetThickness (gsvit_im, pcb_to_gsvit (gc->width));
01488     linewidth = gc->width;
01489     need_brush = 1;
01490   }
01491 
01492   if (lastbrush != gc->brush || need_brush) {
01493     static void *bcache = 0;
01494     hidval bval;
01495     char name[256];
01496     char type;
01497     int r;
01498 
01499     switch (gc->cap) {
01500       case Round_Cap:
01501       case Trace_Cap:
01502         type = 'C';
01503         r = pcb_to_gsvit (gc->width / 2);
01504         break;
01505       default:
01506         case Square_Cap:
01507           r = pcb_to_gsvit(gc->width);
01508           type = 'S';
01509           break;
01510     }
01511     sprintf (name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
01512 /*
01513     if (hid_cache_color(0, name, &bval, &bcache)) {
01514       gc->brush = (gdImagePtr) bval.ptr;
01515     }
01516     else {
01517  */
01518     {
01519       int bg, fg;
01520 
01521       if (type == 'C')
01522         gc->brush = gdImageCreate (2 * r + 1, 2 * r + 1);
01523       else
01524         gc->brush = gdImageCreate (r + 1, r + 1);
01525 
01526       bg = gdImageColorAllocate (gc->brush, 255, 255, 255);
01527       if (hashColor != gdBrushed) {
01528 /*
01529         printf ("hash:%d\n",hashColor);
01530  */
01531         fg = gdImageColorAllocate (gc->brush, color_array[hashColor]->r,color_array[hashColor]->g,color_array[hashColor]->b);
01532       }
01533       else {
01534         fg = gdImageColorAllocate (gc->brush, gc->color->r, gc->color->g, gc->color->b);
01535       }
01536       gdImageColorTransparent (gc->brush, bg);
01537 
01538       /* If we shrunk to a radius/box width of zero, then just use a
01539        * single pixel to draw with.
01540        */
01541       if (r == 0) {
01542         gdImageFilledRectangle (gc->brush, 0, 0, 0, 0, fg);
01543       }  
01544       else {
01545         if (type == 'C')
01546           gdImageFilledEllipse (gc->brush, r, r, 2 * r, 2 * r, fg);
01547         else
01548           gdImageFilledRectangle (gc->brush, 0, 0, r, r, fg);
01549       }
01550       bval.ptr = gc->brush;
01551       hid_cache_color (1, name, &bval, &bcache);
01552     }
01553 
01554     gdImageSetBrush (gsvit_im, gc->brush);
01555     lastbrush = gc->brush;
01556   }
01557 }
01558 
01559 
01560 static void
01561 gsvit_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01562 {
01563   use_gc (gc);
01564 
01565   gdImageRectangle (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1),
01566     pcb_to_gsvit (x2), pcb_to_gsvit (y2), gc->color->c);
01567 }
01568 
01569 
01570 static void
01571 gsvit_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01572 {
01573   use_gc (gc);
01574   gdImageSetThickness (gsvit_im, 0);
01575   linewidth = 0;
01576 
01577   gdImageFilledRectangle (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1),
01578     pcb_to_gsvit (x2), pcb_to_gsvit (y2), gc->color->c);
01579 }
01580 
01581 
01582 struct gsvit_netlist *
01583 gsvit_lookup_net_from_arc (ArcType *targetArc)
01584 {
01585   int i;
01586 
01587   for (i = 0; i < PCB->NetlistLib.MenuN; i++) {
01588     /* For each net in the netlist. */
01589     struct gsvit_netlist *currNet = &gsvit_netlist[i];
01590     int j;
01591 
01592     for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) {
01593       /* For each layer of the current group. */
01594       int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j];
01595 
01596       ARC_LOOP (&(currNet->layer[layer]));
01597       {
01598         if (targetArc == arc)
01599           return (currNet);
01600       }
01601       END_LOOP;
01602     }
01603   }
01604 
01605   return (NULL);
01606 }
01607 
01608 
01609 struct gsvit_netlist *
01610 gsvit_lookup_net_from_line (LineType *targetLine)
01611 {
01612   int i;
01613 
01614   for (i = 0; i < PCB->NetlistLib.MenuN; i++) {
01615     /* For each net in the netlist. */
01616     struct gsvit_netlist* currNet = &gsvit_netlist[i];
01617     int j;
01618 
01619     for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) {
01620       /* For each layer of the current group. */
01621       int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j];
01622 
01623       LINE_LOOP (&(currNet->layer[layer]));
01624       {
01625         if (targetLine == line)
01626           return (currNet);
01627       }
01628       END_LOOP;
01629 
01630     }
01631   }
01632 
01633   return (NULL);
01634 }
01635 
01636 
01637 struct gsvit_netlist *
01638 gsvit_lookup_net_from_polygon (PolygonType *targetPolygon)
01639 {
01640   int i;
01641 
01642   for (i = 0; i < PCB->NetlistLib.MenuN; i++) {
01643     /* For each net in the netlist. */
01644     struct gsvit_netlist* currNet = &gsvit_netlist[i];
01645     int j;
01646 
01647     for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) {
01648       /* For each layer of the current group. */
01649       int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j];
01650 
01651       POLYGON_LOOP (&(currNet->layer[layer]));
01652       {
01653         if (targetPolygon == polygon)
01654           return (currNet);
01655       }
01656       END_LOOP;
01657 
01658     }
01659   }
01660 
01661   return (NULL);
01662 }
01663 
01664 
01665 struct gsvit_netlist *
01666 gsvit_lookup_net_from_pad (PadType *targetPad)
01667 {
01668   int i;
01669 
01670   for (i = 0; i < PCB->NetlistLib.MenuN; i++) {
01671     /* For each net in the netlist. */
01672     struct gsvit_netlist* currNet = &gsvit_netlist[i];
01673 
01674     PAD_LOOP (currNet);
01675     {
01676       if (targetPad == pad)
01677         return (currNet);
01678     }
01679     END_LOOP;
01680 
01681   }
01682 
01683   return (NULL);
01684 }
01685 
01686 
01687 struct gsvit_netlist *
01688 gsvit_lookup_net_from_pv (PinType *targetPv)
01689 {
01690   int i;
01691 
01692   for (i = 0; i < PCB->NetlistLib.MenuN; i++) {
01693     /* For each net in the netlist. */
01694     struct gsvit_netlist* currNet = &gsvit_netlist[i];
01695 
01696     PIN_LOOP (currNet);
01697     {
01698       if (targetPv == pin)
01699         return (currNet);
01700     }
01701     END_LOOP;
01702 
01703     VIA_LOOP (currNet);
01704     {
01705       if (targetPv == via)
01706         return (currNet);
01707     }
01708     END_LOOP;
01709   }
01710 
01711   return (NULL);
01712 }
01713 
01714 
01715 static void
01716 add_hole (struct single_size_drills* drill, int cx, int cy)
01717 {
01718   if (drill->n_holes == drill->n_holes_allocated) {
01719     drill->n_holes_allocated += 100;
01720     drill->holes = (struct drill_hole *) realloc (drill->holes,drill->n_holes_allocated *sizeof (struct drill_hole));
01721   }
01722   drill->holes[drill->n_holes].cx = cx;
01723   drill->holes[drill->n_holes].cy = cy;
01724   drill->holes[drill->n_holes].is_plated = is_plated;
01725   drill->n_holes++;
01726   printf ("holes %d\n", drill->n_holes);
01727 }
01728 
01729 
01736 static int
01737 _drill_size_comparator (const void* _size0, const void* _size1)
01738 {
01739   double size0 = ((const struct single_size_drills*)_size0)->diameter_inches;
01740   double size1 = ((const struct single_size_drills*)_size1)->diameter_inches;
01741   if (size0 == size1)
01742     return 0;
01743   if (size0 < size1)
01744     return -1;
01745   return 1;
01746 }
01747 
01748 
01749 static struct single_size_drills *
01750 get_drill (double diameter_inches, Coord radius)
01751 {
01752   /* See if we already have this size. If so, return that structure. */
01753   struct single_size_drills* drill = bsearch (&diameter_inches,
01754     drills, n_drills, sizeof (drills[0]),
01755     _drill_size_comparator);
01756 
01757   if (drill != NULL)
01758     return( drill);
01759 
01760   /* Haven't seen this hole size before, so make a new structure for it. */
01761   if (n_drills == n_drills_allocated) {
01762     n_drills_allocated += 100;
01763     drills = (struct single_size_drills *) realloc (drills,
01764       n_drills_allocated * sizeof (struct single_size_drills));
01765   }
01766 
01767   /* I now add the structure to the list, making sure to keep the list
01768    * sorted. Ideally the bsearch() call above would have given me the location
01769    * to insert this element while keeping things sorted, but it doesn't. For
01770    * simplicity I manually lsearch() to find this location myself */
01771   {
01772     int i = 0;
01773     for (i = 0; i<n_drills; i++)
01774       if (drills[i].diameter_inches >= diameter_inches)
01775         break;
01776 
01777     if (n_drills != i)
01778       memmove (&drills[i+1], &drills[i],
01779         (n_drills-i) * sizeof (struct single_size_drills));
01780 
01781     drills[i].diameter_inches = diameter_inches;
01782     drills[i].radius = radius;
01783     drills[i].n_holes = 0;
01784     drills[i].n_holes_allocated = 0;
01785     drills[i].holes = NULL;
01786     n_drills++;
01787     return &drills[i];
01788   }
01789 }
01790 
01791 
01792 static void
01793 gsvit_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01794 {
01795   if (x1 == x2 && y1 == y2) {
01796     Coord w = gc->width / 2;
01797     gsvit_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w);
01798     return;
01799   }
01800 
01801   linewidth = -1;
01802   use_gc (gc);
01803   linewidth = -1;
01804 
01805   gdImageSetThickness (gsvit_im, 0);
01806   linewidth = 0;
01807   gdImageLine (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1),
01808     pcb_to_gsvit (x2), pcb_to_gsvit (y2), gdBrushed);
01809 }
01810 
01811 
01812 static void
01813 gsvit_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle)
01814 {
01815   Angle sa, ea;
01816 
01817   /* In gdImageArc, 0 degrees is to the right and +90 degrees is down.
01818    * in pcb, 0 degrees is to the left and +90 degrees is down.
01819    */
01820   start_angle = 180 - start_angle;
01821   delta_angle = -delta_angle;
01822   if (delta_angle > 0) {
01823     sa = start_angle;
01824     ea = start_angle + delta_angle;
01825   }
01826   else {
01827     sa = start_angle + delta_angle;
01828     ea = start_angle;
01829   }
01830 
01831   /* Make sure we start between 0 and 360 otherwise gd does strange
01832    * things.
01833    */
01834   sa = NormalizeAngle (sa);
01835   ea = NormalizeAngle (ea);
01836 
01837 #if 0
01838   printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
01839     cx, cy, width, height, start_angle, delta_angle, sa, ea);
01840   printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
01841     im, SCALE_X (cx), SCALE_Y (cy), SCALE (width), SCALE (height), sa, ea,
01842     gc->color->c);
01843 #endif
01844   use_gc (gc);
01845   gdImageSetThickness (gsvit_im, 0);
01846   linewidth = 0;
01847   gdImageArc (gsvit_im, pcb_to_gsvit (cx), pcb_to_gsvit (cy),
01848     pcb_to_gsvit (2 * width), pcb_to_gsvit (2 * height), sa, ea, gdBrushed);
01849 }
01850 
01851 
01852 static void
01853 gsvit_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
01854 {
01855   use_gc (gc);
01856 
01857   gdImageSetThickness (gsvit_im, 0);
01858   linewidth = 0;
01859   gdImageFilledEllipse (gsvit_im, pcb_to_gsvit (cx), pcb_to_gsvit (cy),
01860     pcb_to_gsvit (2 * radius), pcb_to_gsvit (2 * radius), color_array[hashColor]->c);
01861 
01862   if (save_drill && is_drill)
01863   {
01864     double diameter_inches = COORD_TO_INCH(radius*2);
01865     struct single_size_drills* drill = get_drill (diameter_inches, radius);
01866     add_hole(drill, pcb_to_gsvit(cx), pcb_to_gsvit(cy));
01867       /* convert to inch, flip: will drill from bottom side */
01868 //      COORD_TO_INCH(PCB->MaxWidth  - cx),
01869       /* PCB reverses y axis */
01870 //      COORD_TO_INCH(PCB->MaxHeight - cy));
01871   }
01872 }
01873 
01874 
01875 static void
01876 gsvit_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
01877 {
01878   int i;
01879   gdPoint *points;
01880 
01881   points = (gdPoint *) malloc (n_coords * sizeof (gdPoint));
01882 
01883   if (points == NULL) {
01884     fprintf (stderr, "ERROR:  gsvit_fill_polygon():  malloc failed\n");
01885     exit (1);
01886   }
01887 
01888   use_gc (gc);
01889 
01890   for (i = 0; i < n_coords; i++) {
01891     points[i].x = pcb_to_gsvit (x[i]);
01892     points[i].y = pcb_to_gsvit (y[i]);
01893   }
01894 
01895   gdImageSetThickness (gsvit_im, 0);
01896   linewidth = 0;
01897   gdImageFilledPolygon (gsvit_im, points, n_coords, color_array[hashColor]->c);
01898 
01899   free (points);
01900 }
01901 
01902 
01903 static void
01904 gsvit_calibrate (double xval, double yval)
01905 {
01906   CRASH;
01907 }
01908 
01909 
01910 static void
01911 gsvit_set_crosshair (int x, int y, int a)
01912 {
01913   /* Do nothing. */
01914 }
01915 
01916 
01917 static void
01918 gsvit_draw_pcb_arc (hidGC gc, ArcType *arc)
01919 {
01920   struct gsvit_netlist *net;
01921 
01922   net = gsvit_lookup_net_from_arc (arc);
01923 
01924   if (net) {
01925     hashColor = net->colorIndex;
01926   }
01927   else {
01928     hashColor = PCB->NetlistLib.MenuN;
01929   }
01930 
01931   common_draw_pcb_arc (gc, arc);
01932   hashColor = PCB->NetlistLib.MenuN;
01933 }
01934 
01935 
01936 static void
01937 gsvit_draw_pcb_line (hidGC gc, LineType *line)
01938 {
01939   struct gsvit_netlist *net;
01940 
01941   net = gsvit_lookup_net_from_line (line);
01942 
01943   if (net) {
01944     hashColor = net->colorIndex;
01945   }
01946   else {
01947     hashColor = PCB->NetlistLib.MenuN;
01948   }
01949 
01950   common_draw_pcb_line (gc, line);
01951   hashColor = PCB->NetlistLib.MenuN;
01952 
01953 }
01954 
01955 
01956 void
01957 gsvit_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
01958 {
01959   /* Hijack the fill_pcb_polygon function to get *poly, then proceed
01960    * with the default handler.
01961    */
01962   struct gsvit_netlist *net;
01963 
01964   net = gsvit_lookup_net_from_polygon (poly);
01965 
01966   if (net) {
01967     hashColor = net->colorIndex;
01968   }
01969   else {
01970     hashColor = PCB->NetlistLib.MenuN;
01971   }
01972 
01973   common_fill_pcb_polygon (gc, poly, clip_box);
01974   hashColor = PCB->NetlistLib.MenuN;
01975 }
01976 
01977 
01978 void
01979 gsvit_fill_pcb_pad (hidGC gc, PadType *pad, bool clear, bool mask)
01980 {
01981   struct gsvit_netlist *net = NULL;
01982 
01983   net = gsvit_lookup_net_from_pad(pad);
01984 
01985   if (net) {
01986     hashColor = net->colorIndex;
01987   }
01988   else {
01989     hashColor = PCB->NetlistLib.MenuN;
01990   }
01991 
01992   common_fill_pcb_pad (gc, pad, clear, mask);
01993   hashColor = PCB->NetlistLib.MenuN;
01994 }
01995 
01996 
01997 void
01998 gsvit_fill_pcb_pv (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask)
01999 {
02000   struct gsvit_netlist *net = NULL;
02001 
02002   net = gsvit_lookup_net_from_pv (pv);
02003 
02004   if (net) {
02005     hashColor = net->colorIndex;
02006   }
02007   else {
02008     hashColor = PCB->NetlistLib.MenuN;
02009   }
02010 
02011   common_fill_pcb_pv (fg_gc, bg_gc, pv, drawHole, mask);
02012   hashColor = PCB->NetlistLib.MenuN;
02013 }
02014 
02015 
02016 #include "dolists.h"
02017 
02018 
02019 void
02020 hid_gsvit_init ()
02021 {
02022   memset (&gsvit_hid, 0, sizeof (HID));
02023   memset (&gsvit_graphics, 0, sizeof (HID_DRAW));
02024 
02025   common_nogui_init (&gsvit_hid);
02026   common_draw_helpers_init (&gsvit_graphics);
02027 
02028 //hid_gtk_init();
02029   gsvit_hid.struct_size         = sizeof (HID);
02030   gsvit_hid.name                = "gsvit";
02031   gsvit_hid.description         = "Numerical analysis package export";
02032   gsvit_hid.exporter            = 1;
02033   gsvit_hid.poly_before         = 1;
02034 
02035   gsvit_hid.get_export_options  = gsvit_get_export_options;
02036   gsvit_hid.do_export           = gsvit_do_export;
02037   gsvit_hid.parse_arguments     = gsvit_parse_arguments;
02038   gsvit_hid.set_layer           = gsvit_set_layer;
02039   gsvit_hid.calibrate           = gsvit_calibrate;
02040   gsvit_hid.set_crosshair       = gsvit_set_crosshair;
02041 
02042   gsvit_hid.graphics            = &gsvit_graphics;
02043 
02044   gsvit_graphics.make_gc        = gsvit_make_gc;
02045   gsvit_graphics.destroy_gc     = gsvit_destroy_gc;
02046   gsvit_graphics.use_mask       = gsvit_use_mask;
02047   gsvit_graphics.set_color      = gsvit_set_color;
02048   gsvit_graphics.set_line_cap   = gsvit_set_line_cap;
02049   gsvit_graphics.set_line_width = gsvit_set_line_width;
02050   gsvit_graphics.set_draw_xor   = gsvit_set_draw_xor;
02051   gsvit_graphics.set_draw_faded = gsvit_set_draw_faded;
02052   gsvit_graphics.draw_line      = gsvit_draw_line;
02053   gsvit_graphics.draw_arc       = gsvit_draw_arc;
02054   gsvit_graphics.draw_rect      = gsvit_draw_rect;
02055   gsvit_graphics.fill_circle    = gsvit_fill_circle;
02056   gsvit_graphics.fill_polygon   = gsvit_fill_polygon;
02057   gsvit_graphics.fill_rect      = gsvit_fill_rect;
02058 
02059   /* Hijack these functions because what is passed to fill_polygon is a
02060    * series of polygons (for holes,...).
02061    */
02062   gsvit_graphics.draw_pcb_line = gsvit_draw_pcb_line;
02063   gsvit_graphics.draw_pcb_arc = gsvit_draw_pcb_arc;
02064   gsvit_graphics.draw_pcb_polygon = gsvit_fill_pcb_polygon;
02065 
02066   gsvit_graphics.fill_pcb_polygon = gsvit_fill_pcb_polygon;
02067   gsvit_graphics.fill_pcb_pad = gsvit_fill_pcb_pad;
02068   gsvit_graphics.fill_pcb_pv = gsvit_fill_pcb_pv;
02069 
02070   hid_register_hid (&gsvit_hid);
02071 
02072 #include "gsvit_lists.h"
02073 }