Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Optimize paths in Eagle PCB files for faster CAM processing of GERBER files
import std.xml;
import std.file;
import std.stdio;
import std.conv;
import std.math;
real EPSILON = 1e-2;
real distance_to_line(real fx, real fy, real tx, real ty, real px, real py) {
const vx = tx - fx;
const vy = ty - fy;
const dist = vy*px - vx*py + tx*fy - ty*fx;
const len = sqrt(vx*vx+vy*vy);
return fabs(dist/len);
}
real optimize_vertices(in Tag from, in Tag pto, in Tag point) {
assert(from.name == "vertex");
assert(pto.name == "vertex");
assert(point.name == "vertex");
const fx = to!real(from.attr["x"]);
const fy = to!real(from.attr["y"]);
const tx = to!real(pto.attr["x"]);
const ty = to!real(pto.attr["y"]);
const px = to!real(point.attr["x"]);
const py = to!real(point.attr["y"]);
return distance_to_line(fx, fy, tx, ty, px, py);
}
real optimize_wire(in Tag wire0, in Tag wire1) {
assert(wire0.name == "wire");
assert(wire1.name == "wire");
if (wire0.attr["x2"] != wire1.attr["x1"] || wire0.attr["y2"] != wire1.attr["y1"]) {
return EPSILON;
}
const fx = to!real(wire0.attr["x1"]);
const fy = to!real(wire0.attr["y1"]);
const px = to!real(wire0.attr["x2"]);
const py = to!real(wire0.attr["y2"]);
const tx = to!real(wire1.attr["x2"]);
const ty = to!real(wire1.attr["y2"]);
return distance_to_line(fx, fy, tx, ty, px, py);
}
void deleteChild(Element e, int i) {
e.elements[i] = null;
e.elements = e.elements[0..i] ~ e.elements[i+1..$];
}
void optimize_polygon(Element b) {
assert(b.tag.name == "polygon");
int count;
writeln(" Polygon with ",b.elements.length," vertices");
int last = 0;
for (int t=last+2; t<b.elements.length; ++t) {
const dist = optimize_vertices(b.elements[last].tag, b.elements[t].tag, b.elements[t-1].tag);
if (dist < EPSILON) {
// remove the point
b.deleteChild(--t);
count++;
}
else {
last = t-1;
}
}
if (count) {
writeln(" removed ",count," vertices; ",b.elements.length," left.");
assert(b.elements.length >= 3, "Polygon needs at least 3 vertices.");
b.items = toItems(b.elements);
}
}
void optimize_library(Element library) {
assert(library.tag.name == "library");
assert(library.elements[0].tag.name == "packages");
foreach (a; library.elements[0].elements)
{
assert(a.tag.name == "package");
writeln(" Optimizing package ", a.tag.attr["name"]);
foreach (ii,b; a.elements) {
if (b.tag.name == "polygon") {
optimize_polygon(b);
}
}
}
}
Item[] toItems(Element[] elements) {
auto newline = new Text("\n");
Item[] items;
foreach (e; elements) {
items ~= newline;
items ~= e;
}
return items ~ newline;
}
void optimize_board(Element board) {
assert(board.tag.name == "board");
assert(board.elements[0].tag.name == "plain");
writeln("Optimizing board");
int count;
auto plain = board.elements[0];
for(int i=0; i<plain.elements.length; ++i) {
auto w = plain.elements[i];
if (w.tag.name == "wire") {
while (++i < plain.elements.length) {
auto w1 = plain.elements[i];
if (w1.tag.name != "wire") break;
const dist = optimize_wire(w.tag, w1.tag);
if (dist < EPSILON) {
w.tag.attr["x2"] = w1.tag.attr["x2"];
w.tag.attr["y2"] = w1.tag.attr["y2"];
plain.deleteChild(i--);
count++;
}
else {
w = w1;
}
}
}
}
if (count) {
writeln(" removed ",count," wires");
// FIXME: this removes newlines
plain.items = toItems(plain.elements);
}
/*
if (board.elements[1].tag.name == "libraries") {
foreach (e; board.elements[1].elements) {
writeln("Optimizing library ", e.tag.attr["name"]);
optimize_library(e);
}
}
*/
}
void main(string[] args)
{
if (args.length < 2) {
writeln("Usage: optimize_eagle BRD_OR_LBR [EPSILON]");
return;
}
if (args.length > 2) EPSILON = to!real(args[2]);
writeln("EPSILON=",EPSILON);
writeln("Reading ",args[1]);
string s = cast(string)std.file.read(args[1]);
auto doc = new Document(s);
std.file.write(args[1]~"~", doc.toString);
assert(doc.elements[0].tag.name == "drawing", "Root must be 'drawing'; not an Eagle file?");
if (doc.elements[0].elements[3].tag.name == "library") {
optimize_library(doc.elements[0].elements[3]);
}
else {
optimize_board(doc.elements[0].elements[3]);
}
writeln("Writing ",args[1]);
std.file.write(args[1], doc.toString);
writeln("Done.");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment