Commits

Martin Vejnár committed 1e9987f

Several major fixes.

* Filled polygons no longer consist of a bunch of horizontal lines,
instead a proper path is generated and filled.
* Pads and vias are now added only if LAYER_PADS and LAYER_VIAS are visible, respectively.
* A center drill is added to each pad and via. The size can be overriden (no need for drill-aid).
* A minimum wire width can be set (so that dimension lines can be seen).
* Added a proper GPL header (how sad the original author decided to use it).

Comments (0)

Files changed (1)

-#usage "<b>Eagle schematic exporting tool  version 1.0 </b>\n"
+/* eagle2svg, a ULP script to export schematics and boards to SVG.
+ * Copyright (C) 2008  Nils Springob
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#usage "<b>Eagle schematic exporting tool </b>\n"
        "<p>"
        "This ULP can convert an Eagle CAD schematics into SVG files."
        "<p>"
        
 real VERSION   = 1.1;
 
-/*
- * CHANGELOG================================================
- *
- * 1.1 (??.04.2008): SVG export for board files      
- * 1.0 (16.04.2008): Some bugfixes      
- * 0.2 (11.04.2008): Using CSS for layer-styles      
- * 0.1 (08.03.2008): Initial version    
- *
- */  
-
-/* ==========================================================================
- * License: This file is released under the license of the GNU Public license
- *          Version 2.
- * ==========================================================================*/   
- 
-
-int g_monochrome = 0;
+int g_monochrome = 1;
 int g_only_visible = 1;
 int g_used_layers[];
-
+string g_layer_colors[];
+real g_center_drill = 0.4;
+real g_minimum_wire_width = 0.1;
 
 //------------------------------------------------------
 // generate html color code  
 // SVG output functions
 //------------------------------------------------------
 
-string svgLineStyle(int width, int cap) {
+string svgLineStyle(int width, int cap, int layer) {
   string lineCap="round";
 
   switch (cap) {
   }
 
   string style;
-  sprintf(style, "stroke-width:%f; stroke-linecap:%s",
-    u2mm(width), lineCap);
+  real real_width = u2mm(width);
+  if (real_width < g_minimum_wire_width)
+    real_width = g_minimum_wire_width;
+  sprintf(style, "stroke:%s;stroke-width:%f;stroke-linecap:%s", g_layer_colors[layer], real_width, lineCap);
   return style;    
 }
 
 }
 
 void svgWriteLine(int x1, int y1, int x2, int y2, int layer, string style) {
-  printf("<line class='l%d' x1='%f' y1='%f' x2='%f' y2='%f' style='%s'/>\n",
-    layer,
+  if (g_used_layers[layer]==0) {
+    return;
+  }
+  printf("<line x1='%f' y1='%f' x2='%f' y2='%f' style='%s'/>\n",
     u2mm(x1), u2mm(-y1), 
     u2mm(x2), u2mm(-y2),
     style);
 }
 
 void svgWriteArc(int x1, int y1, int x2, int y2, int radius, char longpath, int layer, string style) {
-  printf("<path class='l%d' d='M %f,%f A %f %f 0 %c 0 %f,%f' style='%s'/>\n",
-    layer,
+  if (g_used_layers[layer]==0) {
+    return;
+  }
+  printf("<path d='M %f,%f A %f %f 0 %c 0 %f,%f' style='%s'/>\n",
     u2mm(x1), u2mm(-y1),
     u2mm(radius), u2mm(radius),
     longpath,
       -angle, 
       u2mm(x1+x2)/2.0, u2mm(-y1-y2)/2.0);
   }   
-  printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f'%s/>\n",
-    layer,
+  printf("<rect x='%f' y='%f' width='%f' height='%f'%s style='fill:%s'/>\n",
     u2mm(x1), u2mm(-y2), 
     u2mm(x2-x1), u2mm(y2-y1),
-    rotation);
+    rotation,
+    g_layer_colors[layer]);
 }
 
 void svgWriteRectCenter(int x, int y, int dx, int dy, real angle, int layer) {
   }
   string rotation = svgTransform(x, y, angle);
 
-  printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f' %s/>\n",
-    layer,
+  printf("<rect x='%f' y='%f' width='%f' height='%f' %s/>\n",
     u2mm(-dx/2), u2mm(-dy/2), 
     u2mm(dx), u2mm(dy),
     rotation);
   real x2 = u2mm(dx)/(2*(1+1.414213562));
   real y2 = u2mm(dy)/(2*(1+1.414213562)); 
 
-  printf("<polygon class='l%d' points='%f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f' %s/>\n",
-    layer,
+  printf("<polygon points='%f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f' %s style='fill:%s'/>\n",
     -x1, -y2, 
     -x2, -y1, 
     x2, -y1, 
     x2, y1, 
     -x2, y1, 
     -x1, y2, 
-    rotation);
+    rotation,
+    g_layer_colors[layer]);
 }
 
 void svgWriteRoundRectCenter(int x, int y, int w, int h, int roundness, real angle, int layer) {
     roundness = h*roundness/200;
   }
 
-  printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f' rx='%f' %s/>\n",
-    layer,
+  printf("<rect x='%f' y='%f' width='%f' height='%f' rx='%f' %s style='fill:%s'/>\n",
     u2mm(-w/2), u2mm(-h/2), 
     u2mm(w), u2mm(h),
     u2mm(roundness),
-    rotation);
+    rotation,
+    g_layer_colors[layer]);
 }
 
 
   if (g_used_layers[layer]==0) {
     return;
   }
-  printf("<circle class='l%d' cx='%f' cy='%f' r='%f' style='stroke-width:%f'/>\n", 
-    layer,
+  printf("<circle cx='%f' cy='%f' r='%f' style='stroke-width:%f;stroke:%s'/>\n", 
     u2mm(x), u2mm(-y),
     u2mm(radius), 
-    u2mm(lwidth));
+    u2mm(lwidth),
+    g_layer_colors[layer]);
 }
 
 void svgWriteDot(int x, int y, int diameter, int layer) {
   if (g_used_layers[layer]==0) {
     return;
   }
-  printf("<circle class='j%d' cx='%f' cy='%f' r='%f'/>\n", 
-    layer,
+  printf("<circle cx='%f' cy='%f' r='%f' style='fill:%s'/>\n", 
     u2mm(x), u2mm(-y),
-    u2mm(diameter)/2.0);
+    u2mm(diameter)/2.0,
+    g_layer_colors[layer]);
 }
 
 
 void svgWritePathStart(int layer, string style) {
-  printf( "<path class='l%d' style='%s' d='", layer, style);
+  printf( "<path style='%s' d='", style);
 }
 
 void svgWritePathSegment(int x1, int y1, int x2, int y2) {
     return;
   }
 
-  string style = svgLineStyle(W.width, W.cap);
+  string style = svgLineStyle(W.width, W.cap, W.layer);
       
   if (W.arc) {
     char longpath;
 // write UL wire
 //------------------------------------------------------
 void write_wire(UL_WIRE W) {
-  if (g_used_layers[W.layer]==0) {
-    return;
-  }
-   
   if ( W.style == WIRE_STYLE_LONGDASH || W.style == WIRE_STYLE_SHORTDASH || W.style == WIRE_STYLE_DASHDOT ) {
     W.pieces(P) {
-      write_piece(P);           
+      write_piece(P);
     }      
   } else if (W.arc) {
-    string style = svgLineStyle(W.arc.width, W.cap);
+    string style = svgLineStyle(W.arc.width, W.cap, W.layer);
     char longpath;
     if( abs(W.arc.angle2-W.arc.angle1) < 180.0 ) {
       longpath='0';
     }
     svgWriteArc(W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, W.arc.radius, longpath, W.layer, style);   
   } else {
-    string style = svgLineStyle(W.width, W.cap);
+    string style = svgLineStyle(W.width, W.cap, W.layer);
     svgWriteLine(W.x1, W.y1, W.x2, W.y2, W.layer, style);
   }
 }
 // write UL rectangle
 //------------------------------------------------------
 void write_rectangle(UL_RECTANGLE R) {
-  if (g_used_layers[R.layer]==0) {
-    return;
-  }
   svgWriteRect(R.x1, R.y1, R.x2, R.y2, R.angle, R.layer);
 }
 
   }
   int cnt=0;
   T.wires(W) {
-    string lineCap;
     if (cnt==0) {
-      string style = svgLineStyle(W.width, W.cap);
+      string style = svgLineStyle(W.width, W.cap, W.layer);
       svgWritePathStart(W.layer, style);
     }
     svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
 // write UL circle
 //------------------------------------------------------
 void write_circle(UL_CIRCLE C) {
-  if (g_used_layers[C.layer]==0) {
-    return;
-  }
   svgWriteCircle(C.x, C.y, C.radius, C.width, C.layer);
 }
 
-
 //------------------------------------------------------
 // write drillsymbol
 //------------------------------------------------------
 //------------------------------------------------------
 // write restring
 //------------------------------------------------------
-void write_restring(int x, int y, int diameter, int shape, int long, real angle, int layer) {
+void write_restring(int x, int y, int diameter, int shape, int drill, int long, real angle, int layer) {
   if (g_used_layers[layer]==0) {
     return;
   }
     case PAD_SHAPE_ROUND:
     default:
       svgWriteDot(x, y, diameter, layer);
+/*      printf("<circle cx='%f' cy='%f' r='%f' style='stroke:%s;stroke-width:%f'/>\n", 
+        u2mm(x), u2mm(-y),
+        u2mm((diameter-drill)/2+drill)/2.0,
+        g_layer_colors[layer],
+        u2mm(diameter-drill)/2.0);*/
+  }
+  if (g_center_drill > 0) {
+    printf("<circle cx='%f' cy='%f' r='%f' style='fill:white'/>\n", 
+      u2mm(x), u2mm(-y),
+      g_center_drill/2.0);
+  } else {
+    printf("<circle cx='%f' cy='%f' r='%f' style='fill:white'/>\n", 
+      u2mm(x), u2mm(-y),
+      u2mm(drill)/2.0);
   }
 }
 
 // write UL pad
 //------------------------------------------------------
 void write_pad(UL_PAD P) {
+  if (g_used_layers[LAYER_PADS] == 0)
+    return;
+
   int layer;
   if (P.flags&PAD_FLAG_STOP) {
-    write_restring(P.x, P.y, P.diameter[LAYER_TSTOP], P.shape[LAYER_TSTOP], 100+P.elongation, P.angle, LAYER_TSTOP);
-    write_restring(P.x, P.y, P.diameter[LAYER_BSTOP], P.shape[LAYER_BSTOP], 100+P.elongation, P.angle, LAYER_BSTOP);
+    write_restring(P.x, P.y, P.diameter[LAYER_TSTOP], P.shape[LAYER_TSTOP], P.drill, 100+P.elongation, P.angle, LAYER_TSTOP);
+    write_restring(P.x, P.y, P.diameter[LAYER_BSTOP], P.shape[LAYER_BSTOP], P.drill, 100+P.elongation, P.angle, LAYER_BSTOP);
   }
   for (layer=LAYER_TOP; layer<=LAYER_BOTTOM; ++layer) {
     if (g_used_layers[layer]) {
-      write_restring(P.x, P.y, P.diameter[layer], P.shape[layer], 100+P.elongation, P.angle, layer);
+      write_restring(P.x, P.y, P.diameter[layer], P.shape[layer], P.drill, 100+P.elongation, P.angle, layer);
     }
   }
   write_drill(P.x, P.y, P.drillsymbol, LAYER_DRILLS);
 // write UL via
 //------------------------------------------------------
 void write_via(UL_VIA V) {
+  if (g_used_layers[LAYER_VIAS] == 0)
+    return;
   int layer;
   if (V.flags&VIA_FLAG_STOP) {
-    write_restring(V.x, V.y, V.diameter[LAYER_TSTOP], V.shape[LAYER_TSTOP], 100, 0.0, LAYER_TSTOP);
-    write_restring(V.x, V.y, V.diameter[LAYER_BSTOP], V.shape[LAYER_BSTOP], 100, 0.0, LAYER_BSTOP);
+    write_restring(V.x, V.y, V.diameter[LAYER_TSTOP], V.shape[LAYER_TSTOP], V.drill, 100, 0.0, LAYER_TSTOP);
+    write_restring(V.x, V.y, V.diameter[LAYER_BSTOP], V.shape[LAYER_BSTOP], V.drill, 100, 0.0, LAYER_BSTOP);
   }
-  for (layer=V.start; layer<=V.end; ++layer) {
-    if (g_used_layers[layer]) {
-      write_restring(V.x, V.y, V.diameter[layer], V.shape[layer], 100, 0.0, layer);
-    }
-  }
+  for (layer=V.start; layer<=V.end; ++layer)
+      write_restring(V.x, V.y, V.diameter[layer], V.shape[layer], V.drill, 100, 0.0, layer);
   write_drill(V.x, V.y, V.drillsymbol, LAYER_DRILLS);
 }
 
   if (g_used_layers[P.layer]==0) {
     return;
   }
+
   int count = 0;
-  printf( "<polygon class='l%d' points='", P.layer);
+  printf( "<polygon points='" );
 
   P.wires(W) {
     if (count == 0) {
 
 }
 
-
 //------------------------------------------------------
 // write filled UL polygon
 //------------------------------------------------------
   if (g_used_layers[P.layer]==0) {
     return;
   }
-  string style;
-  int first=1;
-  
-  P.contours(W) {
-    if (first) {
-      string style = svgLineStyle(W.width, W.cap);
-      svgWritePathStart(P.layer, style);
-      first=0;
+
+  printf( "<path style='fill:%s;stroke:%s;stroke-width:%f;stroke-linejoin:round' d='",
+    g_layer_colors[P.layer], g_layer_colors[P.layer], u2mm(P.width));
+
+  int poly_id = 1;
+  int first = 0;
+
+  while (!first)
+  {
+    first = 1;
+    P.contours(W, poly_id)
+    {
+      if (first) {
+        printf( " M %f,%f", u2mm(W.x1), u2mm(-W.y1));
+        first=0;
+      }
+      printf( " L %f,%f", u2mm(W.x2), u2mm(-W.y2));
     }
-    svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
+    ++poly_id;
   }
-  P.fillings(W) {
-    svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
+
+  poly_id = -1;
+  first = 0;
+  while (!first)
+  {
+    first = 1;
+    P.contours(W, poly_id)
+    {
+      if (first) {
+        printf( " M %f,%f", u2mm(W.x1), u2mm(-W.y1));
+        first=0;
+      }
+      printf( " L %f,%f", u2mm(W.x2), u2mm(-W.y2));
+    }
+    --poly_id;
   }
+
   svgWritePathEnd();
 }
 
     color = htmlcolor(palette(L.color)&0x00ffffff);
   }
   
-  printf ("path.l%d {stroke:%s; fill:none; }\n", L.number, color);
-  printf ("line.l%d {stroke:%s; fill:none; }\n", L.number, color);
-  printf ("circle.l%d {stroke:%s; fill:none; }\n", L.number, color);
-  printf ("circle.j%d {fill:%s; }\n", L.number, color);
-  printf ("rect.l%d {fill:%s; }\n", L.number, color);
-  printf ("text.l%d {font-family:sans-serif; fill:%s; }\n", L.number, color);
-  printf ("polygon.l%d {fill:%s; }\n", L.number, color);
+  g_layer_colors[L.number] = color;
+  
+//  printf ("path.l%d {stroke:%s; fill:none; }\n", L.number, color);
+//  printf ("path.l%d.polygon {stroke:none; fill:%s; }\n", L.number, color);
+//  printf ("line.l%d {stroke:%s; fill:none; }\n", L.number, color);
+//  printf ("circle.l%d {stroke:%s; fill:none; }\n", L.number, color);
+//  printf ("circle.j%d {fill:%s; }\n", L.number, color);
+//  printf ("rect.l%d {fill:%s; }\n", L.number, color);
+//  printf ("text.l%d {font-family:sans-serif; fill:%s; }\n", L.number, color);
+//  printf ("polygon.l%d {fill:%s; }\n", L.number, color);
 }
 
 
   int t = time();
   int pageCount = 0;
   string header =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-  header += "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' ";
+  header += "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' style='fill:none;stroke:none' ";
   header += "width='%fmm' height='%fmm' viewBox='%f %f %f %f'>\n";
 
   int dimX    = B.area.x2-B.area.x1;
   printf("<title>%s</title>\n", encodeText(B.name));
   printf("<desc>generated by eagle2svg %.1f, developed by http://www.nicai-systems.de</desc>\n", VERSION);
 
-  write_board_styles();
+  //write_board_styles();
+  board(B) {
+    B.layers(L) {
+      write_svg_layerStyle(L);
+    }
+  }
   printf ("<g id='surface0'>\n");
 }
 
         }
         dlgCheckBox("Monochrome", g_monochrome);
         dlgCheckBox("Only visible", g_only_visible);
+        dlgHBoxLayout {
+          dlgSpacing(space);
+          dlgLabel("Add center drills in mm:");
+          dlgSpacing(space);
+          dlgRealEdit(g_center_drill, 0, 1000000);
+          dlgSpacing(space);
+        }
+        dlgHBoxLayout {
+          dlgSpacing(space);
+          dlgLabel("Minimum wire width in mm:");
+          dlgSpacing(space);
+          dlgRealEdit(g_minimum_wire_width, 0, 1000000);
+          dlgSpacing(space);
+        }
         dlgStretch(10);
         dlgLabel("developed by <a href='http://www.nicai-systems.de'>http://nibo.nicai-systems.de</a>, based on eagle2ps");
       }