//EAGLE ULP "snap.ulp"
//Copyright (c) 2012-07-09 Andreas Weidner
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#require 5.0600
//Earlier EAGLE versions (from 5.0 upward) MAY be able to run this ULP, but
//were not properly tested
#usage "en:
"
"Snap objects to a grid\n"
"This program moves objects from schematics, boards or libraries, "
"so that their origins (or end points) are on a given grid. The grid "
"size and the objects to snap can be set with a dialog box or the command "
"line."
"© 2012-07-09 Andreas Weidner |
"
"
"
"Usage:"
"- RUN snap [dx [dy]] [group|sheet] [objects]"
"
"
"- Sets the grid size to dx horizontally and dy "
"vertically. If group is used, only objects inside the current "
"group are moved, if sheet is used, only objects on the current "
"schematics sheet are moved. If no objects are given, a snap "
"dialog pops up. If objects are given, the snapping is done "
"immediately (without a dialog). For a list of allowed objects, see "
"below.
"
"Examples:"
"- RUN snap
"
"- Opens the snap dialog and lets the user set all options.
"
"- RUN snap 0.1 0.2
"
"- Sets the grid size to 0.1 horizontally and 0.2 "
"vertically and shows the snap dialog.
"
"- RUN snap 0.05 group all
"
"- Snaps all supported objects belonging to the currently "
"defined group to a grid of 0.05 in both directions.
"
"
"
"Supported objects:"
"
"
"Editor | Objects | "
"Description |
"
"Schematic | "
"gates | Moves gates added from "
"libraries. Junctions and nets connected directly to the gate pins are "
"also moved. |
"
"nets | Moves "
"nets, busses and junctions. Cross-reference labels connected "
"directly to net endpoints are also moved. |
"
"all | Moves "
"all of the above supported schematic objects. |
"
"Board | "
"elements | Moves elements added from "
"libraries. Vias and signal wires connected directly to the element pads "
"or SMDs are also moved. |
"
"signals | Moves "
"signal wires, vias and polygons. |
"
"all | Moves "
"all of the above supported board objects. |
"
"Symbol | pins"
" | Moves pins. If the pin locations "
"are shared with other objects, these are also moved. If a group is "
"defined, it will be changed during program execution. |
"
"all | Moves "
"all of the above supported symbol objects. |
"
"Package | "
"pads | Moves pads. |
"
"smds | Moves "
"SMDs. |
"
"all | Moves "
"all of the above supported package objects. |
"
"
"
"Hints:"
"- The grid size always uses the current editor unit. If you want to "
"use a different unit, use the snap dialog.
"
"- If no dy is given, the vertical grid is equal to the "
"horizontal one. If no grid size is given, the current grid is used.
"
"- Objects are snapped irrespective of their current visibility (even "
"objects from hidden layers are moved). If you want to exclude some "
"objects from snapping, first create a group that does not contain "
"them.
"
"- If group is used, but no group is currently defined, no "
"objects are moved.
"
"- Options can be abbreviated (e.g., gr instead of group) "
"as long as there is no ambiguity (e.g., g could mean either "
"group or gates).
"
"
",
"de: "
"Objekte auf Gitter einrasten\n"
"Dieses Programm verschiebt Objekte im Schaltplan, auf der Platine "
"oder in Bibliotheken, so daß ihre Nullpunkte (oder Endpunkte) auf einem "
"definierten Raster liegen. Rasterabstand und einzurastende Objekte "
"können per Dialogbox oder mit der Kommandozeile festgelegt werden."
"© 2012-07-09 Andreas Weidner |
"
"
"
"Aufruf:"
"- RUN snap [dx [dy]] [group|sheet] [Objekte]"
"
"
"- Setzt den Gitterabstand auf dx horizontal und dy "
"vertikal. Ist group angegeben, werden nur Objekte innerhalb der "
"aktuellen Gruppe verschoben, ist sheet angegeben, werden nur "
"Objekte auf der aktuellen Schaltplanseite verschoben. Sind keine "
"Objekte angegeben, wird ein Auswahldialog angezeigt. Werden "
"Objekte verwendet, findet der Rastvorgang sofort (und ohne "
"Dialogfenster) statt. Eine Liste unterstützter Objekte befindet sich "
"unten.
"
"Beispiele:"
"- RUN snap
"
"- Öffnet den Einrastdialog, in dem der Benutzer alle Optionen "
"einstellt.
"
"- RUN snap 0.1 0.2
"
"- Setzt den Gitterabstand auf 0.1 horizontal und 0.2 "
"vertikal und zeigt den Einrastdialog an.
"
"- RUN snap 0.05 group all
"
"- Verschiebt alle unterstützten Objekte, die sich in der "
"momentan definierten Gruppe befinden, auf ein Raster von 0.05"
" in beiden Richtungen.
"
"
"
"Unterstützte Objekte:"
"
"
"Editor | Objekte | "
"Beschreibung |
"
"Schaltplan | "
"gates | Verschiebt aus Bibliotheken "
"eingefügte Gatter. Direkt mit den Gatteranschlüssen verbundene "
"Netze und Kreuzungspunkte werden ebenfalls verschoben. |
"
"nets | Verschiebt "
"Netze, Busse und Kreuzungspunkte. Direkt mit Netzenden verbundene "
"Querverweistexte werden ebenfalls verschoben. |
"
"all | Verschiebt "
"alle oben angegebenen Schaltplanobjekte. |
"
"Platine | "
"elements | Verschiebt aus Bibliotheken "
"eingefügte Elemente. Direkt mit den Bauteilanschlüssen verbundene "
"Kupferbahnen und Durchkontaktierungen werden ebenfalls verschoben. | "
"
"
"signals | "
"Verschiebt mit Signalen verbundene Kupferbahnen, "
"Durchkontaktierungen und Polygone. |
"
"all | Verschiebt "
"alle oben angegebenen Platinenobjekte. |
"
"Symbol | pins"
" | Verschiebt Gatteranschlüsse. "
"Stimmen deren Positionen mit anderen Objekten überein, werden diese "
"ebenfalls verschoben. Ist eine Gruppe definiert, wird diese während der "
"Programmausführung verändert. |
"
"all | Verschiebt "
"alle oben angegebenen Symbolobjekte. |
"
"Gehäuse | "
"pads | Verschiebt Lötaugen. |
"
"smds | Verschiebt "
"SMD-Lötflächen. |
"
"all | Verschiebt "
"alle oben angegebenen Gehäuseobjekte. |
"
"
"
"Hinweise:"
"- Der Rasterabstand verwendet immer die aktuelle Editor-Einheit. Zur "
"Benutzung einer anderen Einheit kann der Einrastdialog angezeigt "
"werden.
"
"- Ist kein dy angegeben, wird das vertikale Raster gleich dem "
"horizontalen gesetzt. Wird gar kein Gitterabstand angegeben, wird "
"das aktuelle Raster verwendet.
"
"- Objekte werden unabhängig von ihrer aktuellen Sichtbarkeit "
"eingerastet (auch Objekte in ausgeblendeten Ebenen werden verschoben). "
"Wollen Sie einige Objekte vom Einrasten ausnehmen, erzeugen Sie zuerst "
"eine Gruppe ohne sie.
"
"- Wird group übergeben, wenn momentan keine Gruppe definiert "
"ist, wird kein Objekt verschoben.
"
"- Die Optionen können abgekürzt werden (z.B. gr statt group"
"), wenn dadurch keine Mißverständnisse entstehen (z.B. könnte g"
" sowohl group als auch gates bedeuten).
"
//----- FUNCTIONS COPIED FROM THE INCLUDE FILE 'awtools.inc'
//----- (By default, this program uses several functions from an include file
//----- 'awtools.inc'. To make the ULP independent of any includes for easier
//----- distribution, the necessary function have been copied to this file
//----- (unsorted). If 'awtools.inc' IS available and its usage desired,
//----- uncomment the next line and delete all text up to (and including)
//----- 'END OF TEXT COPIED FROM AWTOOLS.INC'
//#include "awtools.inc"
string AWExitCommand="";
//Global string that takes up script commands to execute after ULP exitting
string AWTrim(string Text) {
//Removes leading and trailing blanks, tabs and line feeds from TEXT
string NewText,Character;
NewText=Text;
//Remove leading blanks and tabs
Character=strsub(NewText,0,1);
while ((Character==" ") || (Character=="\t") || (Character=="\n")) {
NewText=strsub(NewText,1);
Character=strsub(NewText,0,1);
}
//Ditto with trailing ones
Character=strsub(NewText,strlen(NewText)-1);
while ((Character==" ") || (Character=="\t") || (Character=="\n")) {
NewText=strsub(NewText,0,strlen(NewText)-1);
Character=strsub(NewText,strlen(NewText)-1);
}
return NewText;
}
int AWParameterFound(string Name,int Abbreviate) {
//Returns 1 if the ULP was started with the (case-insensitive) command line
//parameter NAME (0 otherwise). If ABBREVIATE<>0, the parameter is also found
//when it was typed abbreviated
int Nr;
string Text;
//Exit if no parameter or no name was given
Name=strupr(AWTrim(Name));
if ((argc<2) || (!Name))
return 0;
//Check all given parameters separately
for (Nr=1;Nr=0.05);
}
int OffGridY(int Number) {
//Returns 1 if the Y coordinate NUMBER (in editor units) is off grid
//(0 otherwise)
return (abs((u2mic(Number)/GridY)-round(u2mic(Number)/GridY))*GridY>=0.05);
}
int PointOffGrid(int x,int y) {
//Returns 1 if the point (X,Y) in editor units is off grid (0 otherwise)
return ((OffGridX(x)) || (OffGridY(y)));
}
int PointNeedsMoving(int x,int y,int Grouped) {
//Returns 1 if the point (X,Y) in editor units must be moved (0 otherwise)
if ((PointOffGrid(x,y)) && ((dlgScope!=scopeGroup) || (Grouped)))
return 1;
else
return 0;
}
real SnapX(int Number) {
//Returns the grid X coordinate (in micron) next to NUMBER (in editor units)
return round(u2mic(Number)/GridX)*GridX;
}
real SnapY(int Number) {
//Returns the grid Y coordinate (in micron) next to NUMBER (in editor units)
return round(u2mic(Number)/GridY)*GridY;
}
string SnapPoint(int x,int y) {
//Returns the script command to snap the point (x,y) in editor units
string Result;
sprintf(Result,"MOVE (%f %f) (%f %f);\n",u2mic(x),u2mic(y),SnapX(x),
SnapY(y));
return Result;
}
string SnapGroupedPoint(int x,int y) {
//Returns the script command to snap EVERYTHING that can be selected at the
//point (x,y) in editor units
string Result;
sprintf(Result,"GROUP (%f %f) (%f %f) (%f %f) (>%f %f);\n"+
"MOVE (>%f %f) (%f %f);\n",
u2mic(x)-0.1,u2mic(y)-0.1,u2mic(x)-0.1,u2mic(y)+0.1,
u2mic(x)+0.1,u2mic(y)+0.1,u2mic(x)+0.1,u2mic(y)-0.1,
u2mic(x),u2mic(y),SnapX(x),SnapY(y));
return Result;
}
//----- GRID CALCULATION FUNCTIONS -----
void SetDialogGrid(int GridUnit) {
//Fills the dialog box entries with the current grid distance (in microns),
//converting it to the desired GRIDUNIT
int IntX,IntY;
IntX=GridX/u2mic(1);
IntY=GridY/u2mic(1);
if (GridUnit==GRID_UNIT_MIC) {
dlgGridX=u2mic(IntX);
dlgGridY=u2mic(IntY);
}
else if (GridUnit==GRID_UNIT_MM) {
dlgGridX=u2mm(IntX);
dlgGridY=u2mm(IntY);
}
else if (GridUnit==GRID_UNIT_MIL) {
dlgGridX=u2mil(IntX);
dlgGridY=u2mil(IntY);
}
else if (GridUnit==GRID_UNIT_INCH) {
dlgGridX=u2inch(IntX);
dlgGridY=u2inch(IntY);
}
dlgGridUnit=GridUnit;
OldUnit=GridUnit;
}
void GetDialogGrid(int GridUnit) {
//Extracts the desired grid distance (in micron) from the dialog settings,
//converting the values from the GRIDUNIT
int IntX,IntY;
if (GridUnit==GRID_UNIT_MIC) {
IntX=dlgGridX/u2mic(1);
IntY=dlgGridY/u2mic(1);
}
else if (GridUnit==GRID_UNIT_MM) {
IntX=dlgGridX/u2mm(1);
IntY=dlgGridY/u2mm(1);
}
else if (GridUnit==GRID_UNIT_MIL) {
IntX=dlgGridX/u2mil(1);
IntY=dlgGridY/u2mil(1);
}
else if (GridUnit==GRID_UNIT_INCH) {
IntX=dlgGridX/u2inch(1);
IntY=dlgGridY/u2inch(1);
}
GridX=u2mic(IntX);
GridY=u2mic(IntY);
}
void GetDefaultGrid() {
//Extracts the desired grid from the grid settings of the current editor
//window and the command line parameters and puts them into the corresponding
//global variables
real Distance;
int DistUnit,IntDistance;
//Get the current grid unit from the active window
if (schematic)
schematic(S) {
dlgGridUnit=S.grid.unit;
DistUnit=S.grid.unitdist;
Distance=S.grid.distance;
}
if (board)
board(B) {
dlgGridUnit=B.grid.unit;
DistUnit=B.grid.unitdist;
Distance=B.grid.distance;
}
if (library)
library(L) {
dlgGridUnit=L.grid.unit;
DistUnit=L.grid.unitdist;
Distance=L.grid.distance;
}
if (DistUnit==GRID_UNIT_MIC)
IntDistance=Distance/u2mic(1);
else if (DistUnit==GRID_UNIT_MM)
IntDistance=Distance/u2mm(1);
else if (DistUnit==GRID_UNIT_MIL)
IntDistance=Distance/u2mil(1);
else if (DistUnit==GRID_UNIT_INCH)
IntDistance=Distance/u2inch(1);
GridX=u2mic(IntDistance);
GridY=GridX;
//Convert the microns above into the current grid unit and put the result
//into the dialog fields
SetDialogGrid(dlgGridUnit);
//Return, if no command line parameters were given
if (argc<2)
return;
//The first parameter (if available and a proper number) is always the grid
//distance in X direction (in the current grid unit)
if (strtod(argv[1]))
dlgGridX=strtod(argv[1]);
//The second (if available and a proper number) is the Y distance (otherwise
//the Y distance is the same as the X distance
if ((argc>=3) && (strtod(argv[2]))) {
dlgGridY=strtod(argv[2]);
dlgGridEqual=0;
}
else
dlgGridY=dlgGridX;
//If the command line parameters have changed the dialog's grid settings,
//convet those back to microns for internal use
GetDialogGrid(dlgGridUnit);
//For later passes, the grid settings are ALWAYS given in CORRECT microns, so
//in this case, just read them again
if (AWParameterFound("microns",0)) {
GridX=strtod(argv[1]);
GridY=strtod(argv[2]);
}
}
//----- SCOPE SETTING FUNCTIONS -----
void GetDefaultScope() {
//Calculates the default SCOPE setting based on the currently defined group
//and the command line parameters. The setting ALL is possible under all
//circumstances
dlgScope=scopeAll;
//For the second and third ULP pass, do NOT change the default scope
//automatically, but ONLY take the scope from the ULP parameters
if (!AWParameterFound("microns",0)) {
//In a schematics, use GROUP if a group is defined, or SHEET otherwise
if (sheet) {
sheet(SH)
if (ingroup(SH))
dlgScope=scopeGroup;
else
dlgScope=scopeSheet;
}
//In a board, use GROUP if a group is defined, or ALL otherwise
if (board)
board(B)
if (ingroup(B))
dlgScope=scopeGroup;
//(In the symbol or package editors, use ALL by default)
}
//If the command line parameters say otherwise, use those settings
if (AWParameterFound("group",1))
dlgScope=scopeGroup;
if ((AWParameterFound("sheet",1)) && (schematic))
dlgScope=scopeSheet;
}
//----- OBJECT SETTING FUNCTIONS -----
void ResetSnapObjects() {
//Switches off the snapping procedures for all supported objects and inhibits
//the display of the snap dialog
dlgSnapPins=0;
dlgSnapPads=0;
dlgSnapSMDs=0;
dlgSnapElements=0;
dlgSnapSignals=0;
dlgSnapSignalsPass2=0;
dlgSnapGates=0;
dlgSnapNets=0;
dlgSnapNetsPass2=0;
NoDialog=1;
}
void GetDefaultObjects() {
//Extracts the objects to snap from the command line parameters and decides,
//whether or not the snap dialog needs to be shown. If any objects ARE given
//in the command line, the dialog needs NOT be shown
if (schematic) {
if (AWParameterFound("all",1) || AWParameterFound("gates",1) ||
AWParameterFound("nets",1) || AWParameterFound("netspass2",0))
ResetSnapObjects();
if (AWParameterFound("all",1) || AWParameterFound("gates",1))
dlgSnapGates=1;
if (AWParameterFound("all",1) || (AWParameterFound("nets",1) &&
!AWParameterFound("netspass2",0)))
dlgSnapNets=1;
if (AWParameterFound("netspass2",0))
dlgSnapNetsPass2=1;
}
if (board) {
if (AWParameterFound("all",1) || AWParameterFound("elements",1) ||
AWParameterFound("signals",1) || AWParameterFound("signalspass2",0))
ResetSnapObjects();
if (AWParameterFound("all",1) || AWParameterFound("elements",1))
dlgSnapElements=1;
if (AWParameterFound("all",1) || (AWParameterFound("signals",1) &&
!AWParameterFound("signalspass2",0)))
dlgSnapSignals=1;
if (AWParameterFound("signalspass2",0))
dlgSnapSignalsPass2=1;
}
//Even if objects ARE given in the command line, show the dialog if the
//desired grid settings are erraneous
if ((GridX<0) || ((GridX<1) && (GridX>0)) || (GridX>500000) || (GridY<0) ||
((GridY<1) && (GridY>0)) || (GridY>500000))
NoDialog=0;
}
//----- DIALOG FUNCTIONS -----
void ChangeUnit() {
//Redisplays the dialog's edit fields if the desired grid unit is changed
GetDialogGrid(OldUnit);
SetDialogGrid(dlgGridUnit);
dlgRedisplay();
}
void ShowDistanceGroup() {
//Creates all dialog elements of the 'GRID DISTANCE' group
dlgGroup(AWLocalise(" GRID DISTANCE: "," RASTERABSTAND: ")) {
dlgHBoxLayout {
dlgLabel("X: ");
dlgRealEdit(dlgGridX,0,1e6);
dlgSpacing(20);
dlgCheckBox("=",dlgGridEqual)
dlgAccept(2);
if (!dlgGridEqual) {
dlgSpacing(12);
dlgLabel("Y: ");
dlgRealEdit(dlgGridY,0,1e6);
}
else
dlgLabel("Y");
}
dlgHBoxLayout {
dlgRadioButton(AWLocalise("Micrometer (mic)","Mikrometer (mic)"),
dlgGridUnit)
ChangeUnit();
dlgRadioButton(AWLocalise("Millimeter (mm)","Millimeter (mm)"),
dlgGridUnit)
ChangeUnit();
dlgRadioButton("Mil (1/1000\")",dlgGridUnit)
ChangeUnit();
dlgRadioButton(AWLocalise("Inch (\")","Zoll (\")"),dlgGridUnit)
ChangeUnit();
}
}
}
void ShowScopeGroup() {
//Creates all dialog elements of the 'OBJECT SCOPE' group plus the following
//'OK' and 'Cancel' buttons
dlgGroup(AWLocalise(" OBJECT SCOPE: "," GELTUNGSBEREICH: ")) {
dlgRadioButton(AWLocalise("Only objects in the current group (if "+
"defined)","Nur Objekte aus der aktuellen Gruppe (wenn definiert)"),
dlgScope);
if (schematic) {
dlgRadioButton(AWLocalise("All objects on all schematic sheets (if "+
"available)","Alle Objekte auf allen Schaltplanseiten"),dlgScope);
dlgRadioButton(AWLocalise("Only objects on the current sheet","Nur "+
"Objekte auf der aktuellen Schaltplanseite"),dlgScope);
}
else
dlgRadioButton(AWLocalise("All objects in the current window","Alle "+
"Objekte im aktuellen Fenster"),dlgScope);
}
dlgHBoxLayout {
dlgStretch(0);
dlgPushButton("+OK") {
if (dlgGridEqual)
dlgGridY=dlgGridX;
GetDialogGrid(dlgGridUnit);
//In case of grid settings problems, complain
if ((GridX<1) || (GridY<1))
dlgMessageBox(AWLocalise(":The grid distance must be larger than 1um.",
":Der Rasterabstand muß größer als 1um sein."));
else if ((GridX>500000) || (GridY>500000))
dlgMessageBox(AWLocalise(":The grid distance must be smaller than "+
"500mm.",":Der Rasterabstand muß kleiner als 500mm sein."));
else
dlgAccept(1);
}
dlgPushButton(AWLocalise("-Cancel","-Abbrechen"))
dlgReject(0);
}
}
//----- SNAPPING PROCEDURES FOR THE SYMBOL EDITOR -----
string SnapPins() {
//Returns the script text necessary to snap the desired pins from the
//current symbol
string Result="",Text;
symbol(S)
S.pins(P)
if (PointNeedsMoving(P.x,P.y,ingroup(P)))
//Unfortunately, pins can only be moved while displaying the 'symbols'
//layer. This can create problems, because instead of the desired pin,
//sometimes the WIRE at this point is moved (especially valid for
//'point' pins). Therefore, build a SMALL group around each pin and
//move it INCLUDING the wire(s)
Result+=SnapGroupedPoint(P.x,P.y);
if (Result)
Result="DISPLAY None Symbols;\n"+
"GRID Mic Finest;\n"+
Result+
"GRID Last;\n"+
"DISPLAY Last;\n";
return Result;
}
void SnapSymbol() {
//Snaps all desired objects in the current symbol editor window
int Result=2;
//Do nothing, if the current window is not the symbol editor
if (!symbol)
return;
//If a dialog is desired, show it as often as necessary (until the user has
//selected all options). The dialog returns 0 for 'cancel', 1 for 'OK' and 2
//for 'not yet finished'
if (NoDialog)
Result=1;
while (Result==2)
Result=dlgDialog(AWLocalise("Snap symbol objects","Symbolobjekte "+
"einrasten")) {
ShowDistanceGroup();
dlgGroup(AWLocalise(" OBJECT TYPES: "," OBJEKTTYPEN: "))
dlgCheckBox("Pins",dlgSnapPins);
ShowScopeGroup();
};
//Exit the ULP, if the dialog was cancelled or no objects were selected
if ((!Result) || (!dlgSnapPins))
exit(0);
//If pins are to be snapped, do just that
if (dlgSnapPins)
AWExitCommand+=SnapPins();
//Process the exit command
exit(AWExitCommand);
}
//----- SNAPPING PROCEDURES FOR THE PACKAGE EDITOR -----
string SnapPadsSMDs(int Pads,int SMDs) {
//Returns the script text necessary to snap the desired pads and SMDs from
//the current package
string Result="",Text;
package(P)
P.contacts(C)
if (PointNeedsMoving(C.x,C.y,ingroup(C)))
if (((Pads) && (C.pad)) || ((SMDs) && (C.smd))) {
sprintf(Text,"MOVE %s (%.1f %.1f);\n",C.name,SnapX(C.x),SnapY(C.y));
Result+=Text;
}
if (Result) {
Result="DISPLAY None Top Bottom Pads;\n"+
"GRID Mic Finest;\n"+
Result+
"GRID Last;\n"+
"DISPLAY Last;\n";
}
return Result;
}
void SnapPackage() {
//Snaps all desired objects in the current package editor window
int Result=2;
//Do nothing, if the current window is not the package editor
if (!package)
return;
//If a dialog is desired, show it as often as necessary (until the user has
//selected all options). The dialog returns 0 for 'cancel', 1 for 'OK' and 2
//for 'not yet finished'
if (NoDialog)
Result=1;
while (Result==2)
Result=dlgDialog(AWLocalise("Snap package objects","Gehäuseobjekte "+
"einrasten")) {
ShowDistanceGroup();
dlgGroup(AWLocalise(" OBJECT TYPES: "," OBJEKTTYPEN: ")) {
dlgHBoxLayout {
dlgCheckBox("Pads",dlgSnapPads);
dlgCheckBox("SMDs",dlgSnapSMDs);
}
}
ShowScopeGroup();
};
//Exit the ULP, if the dialog was cancelled or no objects were selected
if ((!Result) || ((!dlgSnapPads) && (!dlgSnapSMDs)))
exit(0);
//If objects are to be snapped, do just that
if ((dlgSnapPads) || (dlgSnapSMDs))
AWExitCommand+=SnapPadsSMDs(dlgSnapPads,dlgSnapSMDs);
//Process the exit command
exit(AWExitCommand);
}
//----- POINT LIST FUNCTIONS -----
//Snapping vias/wires or junctions/nets is NOT so trivial, because when moving
//ONE (line end) point, several others connected to it might also be moved
//automatically. Therefore, don't move these objects separately, but keep a
//list of POINTS to be moved and do the whole moving in several passes. The
//idea for this method of moving was taken from the CadSoft ULPs
//'snap-on-grid-sch.ulp' and 'cmd-snap-board.ulp' (even though the actual
//source code wasn't)
int PointX[],PointY[],PointLayer[],PointCount=0;
//The point list: (X,Y) coordinates, point layer, list size
int PointLayerUsed[];
//A separate entry for each layer defines whether this layer contains
//objects that need moving (1) or not (0)
int IsNewPoint(int x,int y,int Layer) {
//Returns 1 if the point (X,Y) on the LAYER does NOT yet exist in the point
//list (0 otherwise)
int Nr;
for (Nr=0;Nr