#usage "Snap objects in a board\n"
"
"
"Snaps components, wires and vias of the current "
"board to a given grid. "
"If 'Show script' is checked, you can edit the MOVE commands "
"before they are executed. So you are able to exclude certain "
"elements from the snap procedure."
"
"
"Author: support@cadsoft.de"
// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
real GridDist = 50.0;
enum {unitINCH, unitMIL, unitMM, unitMIC};
string h, cmd = "";
int unit = unitMIL; // predefined unit, can be changed to unitMM, unitINCH, unitMIC
int show_script = 1; // predefined value for button "Show script"
int Result;
string Status = "";
// get project path, if in board or schematic, otherwise library path
string get_project_path() {
string s = "", p = "";;
if (library) { library(L) s = L.name;}
if (board) { board(B) s = B.name;}
if (schematic){ schematic(S) s = S.name;}
char c = '/';
int pos = strrchr(s, c);
if (pos >= 0) {
p = strsub(s, 0, pos + 1);
}
return p;
}
real u2unit(int u) {
if (unit == unitMIL)
return u2mil(u);
if (unit == unitMM)
return u2mm(u);
if (unit == unitINCH)
return u2inch(u);
if (unit == unitMIC)
return u2mic(u);
}
real snap(int n) { // returns next grid point
return round(u2unit(n) / GridDist) * GridDist;
}
int n = 0, x[], y[], l[], UsedLayers[];
int isNew(int X, int Y, int L) {
for (int i = 0; i < n; i++) {
if (x[i] == X && y[i] == Y && (l[i] == L || l[i] == LAYER_VIAS ))
return 0;
}
return 1;
}
void Move(int Layer) {
if (UsedLayers[Layer]) {
h = ""; sprintf(h, "DISPLAY NONE %d;\n", Layer); cmd += h;
// Snap the signal wires and vias:
for (int i = 0; i < n; i++) {
if (l[i] == Layer && (u2unit(x[i]) != snap(x[i]) || u2unit(y[i]) != snap(y[i]))) {
h = ""; sprintf(h, "MOVE (%f %f) (%f %f);\n", u2unit(x[i]), u2unit(y[i]), snap(x[i]), snap(y[i])); cmd += h;
}
}
}
}
void snap_to_grid (void) {
board(B) {
// Collect all (unique!) signal wire and via coordinates:
B.signals(S) {
Status = "Signal: "+S.name; dlgRedisplay();
S.vias(V) {
UsedLayers[LAYER_VIAS] = 1;
x[n] = V.x;
y[n] = V.y;
l[n] = LAYER_VIAS;
n++;
}
S.wires(W) {
UsedLayers[W.layer] = 1;
if (isNew(W.x1, W.y1, W.layer)) {
x[n] = W.x1;
y[n] = W.y1;
l[n] = W.layer;
n++;
}
if (isNew(W.x2, W.y2, W.layer)) {
x[n] = W.x2;
y[n] = W.y2;
l[n] = W.layer;
n++;
}
}
}
// Remember the active layers:
int ActiveLayers[];
B.layers(L) {
ActiveLayers[L.number] = L.visible;
}
if (unit == unitMIL) {
h = ""; sprintf(h, "GRID MIL FINEST;\n"); cmd += h;
}
if (unit == unitMM) {
h = ""; sprintf(h, "GRID MM FINEST;\n"); cmd += h;
}
if (unit == unitINCH) {
h = ""; sprintf(h, "GRID INCH FINEST;\n"); cmd += h;
}
if (unit == unitMIC) {
h = ""; sprintf(h, "GRID MIC FINEST;\n"); cmd += h;
}
// Go through the used layers (this avoids problems with wires on different
// layers that are selected at the same coordinates):
for (int u = LAYER_TOP; u <= LAYER_BOTTOM; u++)
Move(u);
Move(LAYER_VIAS);
// Reactivate the active layers:
h = ""; sprintf(h, "DISPLAY"); cmd += h;
for (int j = 1; j < 256; j++)
if (ActiveLayers[j]) {
h = ""; sprintf(h, " %d", j); cmd += h;
}
h = ""; sprintf(h, ";\n"); cmd += h;
// Snap the elements:
B.elements(E) {
Status = "Element: "+E.name; dlgRedisplay();
if (u2unit(E.x) != snap(E.x) || u2unit(E.y) != snap(E.y)) {
if (show_script) {
h = ""; sprintf(h, "SHOW %s;\n", E.name); cmd += h;
}
h = ""; sprintf(h, "MOVE %s (%f %f);\n", E.name, snap(E.x), snap(E.y)); cmd += h;
}
}
h = ""; sprintf(h, "GRID LAST;\n"); cmd += h;
}
}
//---- main ----------------------------------------------------------------------
if (project.board && project.schematic) {
project.board(B) { project.schematic(S) {
dlgMessageBox("Good -- you have both open!\nBoard = " + B.name + ", Schematic = " + S.name);
B.elements(E) {
if (E.package.name == "2,54/0,8") {
h = ""; sprintf(h, "%s@%d, %d", E.name, E.x, E.y);
dlgMessageBox(h);
}
}
} }
}
exit(0);
if (!board) {
dlgMessageBox(usage + "
ERROR: No board!\nThis program can only work in the board editor.");
exit(1);
}
dlgDialog("Snap Packages/Wires/Vias") {
dlgHBoxLayout {
dlgHBoxLayout {
dlgGroup("Unit") {
dlgRadioButton("&inch", unit);
dlgRadioButton("&mil", unit);
dlgRadioButton("&mm", unit);
dlgRadioButton("&mic", unit);
dlgSpacing(20);
dlgLabel("Snap grid ");
dlgRealEdit(GridDist, 0.0001, 1000);
}
}
dlgSpacing(10);
dlgVBoxLayout {
dlgSpacing(10);
dlgCheckBox("&Show script", show_script);
dlgLabel(Status, 1);
dlgHBoxLayout {
dlgPushButton("+&Snap") {Status = "Busy...";
dlgRedisplay();
snap_to_grid();
dlgAccept();
}
dlgPushButton("-&Cancel") exit(0);
}
dlgSpacing(7);
}
}
};
Result = 1;
if (show_script) {
Result = dlgDialog("Edit Commands") {
dlgVBoxLayout {
dlgLabel("Edit only if you are sure what you do!");
dlgTextEdit(cmd);
}
dlgHBoxLayout {
dlgPushButton("+Execute") {snap_to_grid(); dlgAccept();}
dlgPushButton("-Quit") dlgReject();
dlgPushButton("+Save") {
string dest = dlgFileSave("Save Script File", get_project_path()+"snap.scr", "*.scr");
if (dest != "") output(dest, "wt") {printf(cmd);}
}
}
};
}
if (!Result) exit(0);
exit(cmd);