1018 lines
43 KiB
Plaintext
1018 lines
43 KiB
Plaintext
|
|
|
||
|
|
#usage "en:<b>export 3d-data from board to IDF-FileFormat</b><p>"
|
||
|
|
"More info can be found here: .../eagle.../doc/generate_3d_data_eng.pdf<br>"
|
||
|
|
"<author>Original author: Uploaded by Neubacher Andreas from Commend International GmbHh<br>"
|
||
|
|
"co-Author: alf@cadsoft.de</author><p>"
|
||
|
|
,
|
||
|
|
"de:<b>export 3d-data from board to IDF-FileFormat</b><p>"
|
||
|
|
"Im Layer 50 muß eine Kopie der Boardkontour des Layer 20 angelegt werden. Die Wirebreite in Micron "
|
||
|
|
"ergibt die Boarddicke in mm.<br>"
|
||
|
|
"Die Bordkontour kann entweder im Board lebst oder in einem Package angelegt werden, es muß nur die "
|
||
|
|
"obenstehende Bedingung eingehalten werden.<br>"
|
||
|
|
"Um in einem Board einen Durchbruch zu erzeugen, kann man entweder im Board selbst oder in einem Package "
|
||
|
|
"eine Kontur mit der Wirebreite von 0 im Layer 50 anlegen.<br>"
|
||
|
|
"<author>Original author: Uploaded by Neubacher Andreas from Commend International GmbHh<br>"
|
||
|
|
"co-Author: alf@cadsoft.de</author><p>"
|
||
|
|
|
||
|
|
#require 6.0600
|
||
|
|
string UlpVersion = "1.9";
|
||
|
|
|
||
|
|
string Docuemantpath = "Weiter Infos finden sie im Dokumentenordner unter " + path_doc[0] + "/generate_3d_data_eng.pdf<br>";
|
||
|
|
|
||
|
|
|
||
|
|
//############################################################################
|
||
|
|
// Author: Andy Neubacher
|
||
|
|
// Version | Date | log
|
||
|
|
//---------+------------+-----------------------------------------------------
|
||
|
|
// v1.9 | 2014-04-08 | - Now can change the filedirectory an filename
|
||
|
|
// select Top and or Bottom side of parts to export
|
||
|
|
// v1.8 | 2014-04-01 | - Cutout und Koordinaten berichtigt (nur beim ersten Wire, Anfang und Endkoordinate ausgeben)
|
||
|
|
// dann immer nur die 2. Koordinate bis die erste Koordinate wieder erreicht ist.
|
||
|
|
// - LoopCounter für geschlossene Konturen (Durchbruch/Cutout) wieder berichtigt.
|
||
|
|
//
|
||
|
|
// v1.7 | 2014-01-20 | - draw also pad-holes
|
||
|
|
// v1.6 | 2013-12-19 | - LoopCounter für geschlossene Konturen (Durchbruch/Cutout).
|
||
|
|
// Die Bedingung für die Erkennung der einzelnen Konturen ist:
|
||
|
|
// 1. Die allererste Kontour im Layer 50 ist die Boardkontur,
|
||
|
|
// was bedeutet, diese Kontour muss als allererste Kontur gezeichnet werden.
|
||
|
|
// 2. Jede weitere Kontur wird als Cutout betrachtet, und es wird keine Überprüfung
|
||
|
|
// vorgenommen, ob diese Kontur innerhalb oder ausserhalb der Board-Dimension ist.
|
||
|
|
// 3. Jede Kontur muss durchgehend gezeichnet und geschlossen sein.
|
||
|
|
// Das bedeutet, man darf innerhalb einer Kontur nicht an beliebigen Punkten
|
||
|
|
// das (WIRE) zeichnen unterbrechen, und an einer anderen Stelle wieder beginnen,
|
||
|
|
// also dem vorher unterbrochenen *Ende* entgegen zeichnen.
|
||
|
|
//
|
||
|
|
// v1.5 | 2013-12-18 | - file renamed and now without version, for use in Text-Menu
|
||
|
|
// | | - draw board cutout
|
||
|
|
// | | - ++CutoutNumSegments change to CutoutNumSegments++
|
||
|
|
// alf@cadsoft.de
|
||
|
|
// v1.4 | 2013-12-11 | - correct Board outline Curve
|
||
|
|
// | | - correct Pre- to Post-Increment in all Functions
|
||
|
|
// | | - fixed by Angelo.Cuccato@bogen-electronic.com
|
||
|
|
// v1.3 | 2013-03-14 | - correct using ARC coorinates
|
||
|
|
// v1.2 | 2013-01-14 | - Link in description to download page - fixes by alf@cadsoft.de
|
||
|
|
// v1.1 | 2012-12-04 | - korrect Loop Label for contours in layer Dimension - fixes by alf@cadsoft.de
|
||
|
|
// v1.0 | 2012-08-20 | - more resolution %.6f of coordinates - fixes by alf@cadsoft.de
|
||
|
|
// v0.9 | 2012-02-08 | - used function u2mm() for Z-axis value - fixes by alf@cadsoft.de
|
||
|
|
// | |
|
||
|
|
// v0.8 | 2011-05-31 | - changed characters that caused import problems
|
||
|
|
// | | - changed output file extension to .emn and .emp
|
||
|
|
// | | - fixes by morten@riftlabs.com
|
||
|
|
// | |
|
||
|
|
// v0.7 | 2006-10-24 | - outline of board can also be drawn direct in brd-file
|
||
|
|
// | | - any hole is taken from devices and board direct
|
||
|
|
// | | - close open polygons on request
|
||
|
|
// | | - drill vias on request
|
||
|
|
// | | - bugfix : error if device contains more than one poly on top and bottom
|
||
|
|
// | | - bugfix : sorting of points possible failed if polygon was open
|
||
|
|
// | | - bugfix : partheights on bottomlayer were ignored
|
||
|
|
// v0.6 | 2006-08-31 | now multiple partheights are possible
|
||
|
|
// v0.5 | 2006-08-25 | modification to 'RIR-standard'
|
||
|
|
// v0.4 | 2005-11-09 | 1st export of a real board+parts successfull
|
||
|
|
// v0.3 | 2005-11-03 | correct mirrors at top and bottom side
|
||
|
|
// v0.2 | 2005-10-21 | 1st working IDF-data
|
||
|
|
// v0.1 | 2005-09-30 | start of project
|
||
|
|
//---------+------------+-----------------------------------------------------
|
||
|
|
//
|
||
|
|
// HOWTO:
|
||
|
|
// Create your board outline on layer 50.
|
||
|
|
// In your library, draw the component outlines on layer 57 (tCad) and use the line thickness to set component height.
|
||
|
|
// 1000 mic = 1 mm (e.g. if your grid is in mm, then a line thickness of 0.001 equals a component height of 1 mm).
|
||
|
|
// More info can be found here: ftp://ftp.cadsoft.de/eagle/userfiles/ulp/generate_3d_data_eng.pdf
|
||
|
|
//
|
||
|
|
//############################################################################
|
||
|
|
|
||
|
|
|
||
|
|
int Layer3dBoardDimension = 50;
|
||
|
|
int tLayer3Ddata = 57;
|
||
|
|
int bLayer3Ddata = 58;
|
||
|
|
int SelectSide[] = { 1, 1 }; // select Part output on side Top / Bottom
|
||
|
|
int maxCutoutLineWidth = 0; // -->> is linewidth 0.0 -> line is a cutout ??
|
||
|
|
string UlpName = filename(argv[0]); // gets ulp name
|
||
|
|
|
||
|
|
|
||
|
|
// partoptions
|
||
|
|
int NumParts; // number of parts
|
||
|
|
string PartName[]; // name of part
|
||
|
|
|
||
|
|
// vars for polygon calculation
|
||
|
|
int NumSegments = 0; // number of points
|
||
|
|
int PointX1[]; // start x
|
||
|
|
int PointY1[]; // start y
|
||
|
|
int PointX2[]; // end x
|
||
|
|
int PointY2[]; // end y
|
||
|
|
int SegmentType[]; // LINE, ARC, CIRCLE
|
||
|
|
real SegmentCurve[]; // used by ARCs : - if drawn CCW, + if drawn CW
|
||
|
|
int SegmentWidth[]; // linewitdh = partheight
|
||
|
|
|
||
|
|
int CutoutNumSegments = 0;
|
||
|
|
int CutoutPointX1[]; // start x
|
||
|
|
int CutoutPointY1[]; // start y
|
||
|
|
int CutoutPointX2[]; // end x
|
||
|
|
int CutoutPointY2[]; // end y
|
||
|
|
int CutoutSegmentType[]; // LINE, ARC, CIRCLE
|
||
|
|
int CutoutSegmentCurve[]; // used by ARCs : -180 if drawn CCW, +180 if drawn CW
|
||
|
|
int CutoutSegmentWidth[]; // linewitdh = partheight
|
||
|
|
|
||
|
|
int LoopCounter = 0; // 2015-04-02 für Boardoutline und Cutoutline
|
||
|
|
|
||
|
|
|
||
|
|
enum { LINE = 1, ARC = 2, CIRCLE = 3 };
|
||
|
|
enum { CUTOUT = 0, OUTLINE = -1 };
|
||
|
|
enum { false = 0, true = 1};
|
||
|
|
string Type[];
|
||
|
|
Type[0] = "0";
|
||
|
|
Type[LINE] = "LINE";
|
||
|
|
Type[ARC] = "ARC";
|
||
|
|
Type[CIRCLE] = "CIRCLE";
|
||
|
|
|
||
|
|
// vars for library
|
||
|
|
int NumPacInLib = 0; // number of pacs in library
|
||
|
|
int PacIn_LIB_heights[]; // if 0 = only one partheight, if != 0 more than one height
|
||
|
|
real PacIn_LIB_angle[]; // rotation of part in board
|
||
|
|
string PacIn_LIB_name[]; // names of pack's in library
|
||
|
|
int PacIn_LIB_Device_mountside[]; // TOP, BOTTOM
|
||
|
|
string PacIn_LIB_SubPart_mountside[]; // mountside of subparts
|
||
|
|
|
||
|
|
|
||
|
|
int NumCutouts = 0; // number of holes in the pcb (drills, millings)
|
||
|
|
int OutlineInDeviceFound = false; // is outline drawn in device symbol
|
||
|
|
|
||
|
|
int CloseOpenPoly = false; // close polygon if gap is smaller than ...mm
|
||
|
|
real MaxGapWidth = 0.1; // value of maximum gap to close
|
||
|
|
|
||
|
|
int DrillViaHoles = true; // drill via-holes in pcb
|
||
|
|
real MinViaHoleDia = 0.254; // diameter of drill
|
||
|
|
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void CollectPartData(UL_BOARD brd) { // read out all parts
|
||
|
|
NumParts = 0;
|
||
|
|
brd.elements(E) {
|
||
|
|
PartName[NumParts] = E.name;
|
||
|
|
PacIn_LIB_angle[NumParts] = -1; // fill with invalid rotation and ...
|
||
|
|
PacIn_LIB_Device_mountside[NumParts] = -1; // fill with invalid mountside (mirror) for "void IDF_LibaryElectrical(UL_BOARD BRD)" function
|
||
|
|
PacIn_LIB_heights[NumParts] = 0; // part is only one package
|
||
|
|
NumParts++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_Circle(int x1, int y1, int x2, int y2, int type) { // output circle to file in IDF format
|
||
|
|
int loopcount = 0;
|
||
|
|
if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
|
||
|
|
printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
|
||
|
|
printf("%d %.6f %.6f 360\n", loopcount, u2mm(x2), u2mm(y2));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_Arc(int x1, int y1, int x2, int y2, real angle, int type, int first) { // output arc to file in IDF format
|
||
|
|
int loopcount = 0;
|
||
|
|
if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
|
||
|
|
if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
|
||
|
|
printf("%d %.6f %.6f %.1f\n", loopcount, u2mm(x2), u2mm(y2), angle);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_Line(int x1, int y1, int x2, int y2, int type, int first) { // output line to file in IDF format
|
||
|
|
int loopcount = 0;
|
||
|
|
if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
|
||
|
|
if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
|
||
|
|
printf("%d %.6f %.6f 0\n", loopcount, u2mm(x2), u2mm(y2));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void OutputLines(int originx, int originy, int type) { // write to file
|
||
|
|
int first = 1;
|
||
|
|
int i = 0;
|
||
|
|
int startx = PointX1[i];
|
||
|
|
int starty = PointY1[i];
|
||
|
|
for(i = 0; i < NumSegments; i++) {
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
switch(SegmentType[i]) {
|
||
|
|
case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], type, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type);
|
||
|
|
LoopCounter++;
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
startx = PointX1[i+1];
|
||
|
|
starty = PointY1[i+1];
|
||
|
|
first = 1;
|
||
|
|
break;
|
||
|
|
default : string s;
|
||
|
|
sprintf(s, "Unknown type in Segment %d", i);
|
||
|
|
if (dlgMessageBox(s, "OK", "esc") != 0) exit(-182);
|
||
|
|
}
|
||
|
|
if (startx == PointX2[i] && starty == PointY2[i]) {
|
||
|
|
first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
|
||
|
|
startx = PointX1[i+1];
|
||
|
|
starty = PointY1[i+1];
|
||
|
|
LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void OutputBoardOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant
|
||
|
|
int first = 1;
|
||
|
|
int i = 0;
|
||
|
|
int startx = PointX1[i];
|
||
|
|
int starty = PointY1[i];
|
||
|
|
for(i = 0; i < NumSegments; i++) {
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
switch(SegmentType[i]) { // 2013-12-18
|
||
|
|
case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], CUTOUT, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT);
|
||
|
|
LoopCounter++;
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
startx = PointX1[i+1];
|
||
|
|
starty = PointY1[i+1];
|
||
|
|
first = 1;
|
||
|
|
break;
|
||
|
|
default : string s;
|
||
|
|
sprintf(s, "Unknown type in Segment %d", i);
|
||
|
|
}
|
||
|
|
if (startx == PointX2[i] && starty == PointY2[i]) {
|
||
|
|
first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
|
||
|
|
startx = PointX1[i+1];
|
||
|
|
starty = PointY1[i+1];
|
||
|
|
LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
void OutputBoardCutOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant
|
||
|
|
int first = 1;
|
||
|
|
int i = 0;
|
||
|
|
int startx = CutoutPointX1[i];
|
||
|
|
int starty = CutoutPointY1[i];
|
||
|
|
for(i = 0; i < CutoutNumSegments; i++) {
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
switch(CutoutSegmentType[i]) { // 2013-12-18
|
||
|
|
case LINE : IDF_Line(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case ARC : IDF_Arc(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CutoutSegmentCurve[i], CUTOUT, first);
|
||
|
|
first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
|
||
|
|
// bis zum Ende sprich schliessen der Schleife
|
||
|
|
break;
|
||
|
|
case CIRCLE : IDF_Circle(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT);
|
||
|
|
LoopCounter++;
|
||
|
|
NumCutouts = LoopCounter;
|
||
|
|
startx = CutoutPointX1[i+1];
|
||
|
|
starty = CutoutPointY1[i+1];
|
||
|
|
first = 1;
|
||
|
|
break;
|
||
|
|
default : string s;
|
||
|
|
sprintf(s, "Unknown type in Segment %d", i);
|
||
|
|
}
|
||
|
|
if (startx == CutoutPointX2[i] && starty == CutoutPointY2[i]) {
|
||
|
|
first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
|
||
|
|
startx = CutoutPointX1[i+1];
|
||
|
|
starty = CutoutPointY1[i+1];
|
||
|
|
LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int IsPointEqual (int x1, int y1, int x2, int y2) { // really need a func-description ??
|
||
|
|
if(x1 == x2 && y1 == y2) return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
real getPartHeight() { // returns maximum partlevel
|
||
|
|
real ret = u2mm(SegmentWidth[0])*1000.0; // 2012-02-08
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int IsPointInCircle(int target_x, int target_y, int circle_x, int circle_y, real radius) {
|
||
|
|
real dist,a,b;
|
||
|
|
a = abs(target_y-circle_y);
|
||
|
|
b = abs(target_x-circle_x);
|
||
|
|
// calculate distance
|
||
|
|
dist = sqrt(a*a + b*b);
|
||
|
|
if(dist <= radius) return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
//int GetArcOptions(UL_WIRE w) { // is arc drawn CW or CCW
|
||
|
|
// if(IsPointEqual(w.x1, w.y1, w.x2, w.y2)) return (w.arc.angle1 - w.arc.angle2);
|
||
|
|
// else return (w.arc.angle2 - w.arc.angle1);
|
||
|
|
//}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int DataOnLayerPresent(UL_ELEMENT E, int layer) {
|
||
|
|
E.package.circles(CIR) { // circle found
|
||
|
|
if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) return true;
|
||
|
|
}
|
||
|
|
E.package.wires(W) {
|
||
|
|
if(W.arc) { // arc found
|
||
|
|
if(W.layer == layer && W.width > maxCutoutLineWidth) return true;
|
||
|
|
}
|
||
|
|
else { // straight line found
|
||
|
|
if(W.layer == layer && W.width > maxCutoutLineWidth) return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false; // no 3d-data on given layer found
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void CollectRemainingPoints(int start, int nr) {
|
||
|
|
int i;
|
||
|
|
for(i = 0; i < nr; i++) {
|
||
|
|
PointX1[i] = PointX1[i+start];
|
||
|
|
PointY1[i] = PointY1[i+start];
|
||
|
|
PointX2[i] = PointX2[i+start];
|
||
|
|
PointY2[i] = PointY2[i+start];
|
||
|
|
SegmentType[i] = SegmentType[i+start];
|
||
|
|
SegmentCurve[i] = SegmentCurve[i+start];
|
||
|
|
SegmentWidth[i] = SegmentWidth[i+start];
|
||
|
|
}
|
||
|
|
NumSegments = nr;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int SortPointsEx (void) { // sort all points to a continous polygon
|
||
|
|
int i;
|
||
|
|
int ptfound;
|
||
|
|
int ResultPointX1[]; // start x
|
||
|
|
int ResultPointY1[]; // start y
|
||
|
|
int ResultPointX2[]; // end x
|
||
|
|
int ResultPointY2[]; // end y
|
||
|
|
int ResultSegmentType[]; // SegmentType
|
||
|
|
int ResultSegmentCurve[]; // options of segment (only used for ARCs)
|
||
|
|
int ResultSegmentWidth[]; // width of line
|
||
|
|
int PointUsed[];
|
||
|
|
enum { NOT_FOUND = 0, FOUND = 1, ERROR = 2 };
|
||
|
|
enum { NOT_USED = 0, USED = 1 };
|
||
|
|
for(i = 0; i < NumSegments; i++) PointUsed[i] = NOT_USED;
|
||
|
|
|
||
|
|
ResultPointX1[0] = PointX1[0]; // startpoint
|
||
|
|
ResultPointY1[0] = PointY1[0];
|
||
|
|
ResultPointX2[0] = PointX2[0];
|
||
|
|
ResultPointY2[0] = PointY2[0];
|
||
|
|
ResultSegmentType[0] = SegmentType[0];
|
||
|
|
ResultSegmentWidth[0] = SegmentWidth[0];
|
||
|
|
ResultSegmentCurve[0] = SegmentCurve[0];
|
||
|
|
PointUsed[0] = USED;
|
||
|
|
|
||
|
|
for(int x=1; x<NumSegments; x++) {
|
||
|
|
i = 1;
|
||
|
|
ptfound = NOT_FOUND;
|
||
|
|
do {
|
||
|
|
if(!PointUsed[i]) {
|
||
|
|
// search left point of segment in list
|
||
|
|
if( IsPointEqual(PointX1[i], PointY1[i], ResultPointX2[x-1], ResultPointY2[x-1]) ) { // x1,y1 = startpoint | x2,y2 = endpoint
|
||
|
|
ptfound = FOUND;
|
||
|
|
PointUsed[i] = USED;
|
||
|
|
ResultPointX1[x] = PointX1[i];
|
||
|
|
ResultPointY1[x] = PointY1[i];
|
||
|
|
ResultPointX2[x] = PointX2[i];
|
||
|
|
ResultPointY2[x] = PointY2[i];
|
||
|
|
ResultSegmentType[x] = SegmentType[i];
|
||
|
|
ResultSegmentWidth[x] = SegmentWidth[i];
|
||
|
|
ResultSegmentCurve[x] = SegmentCurve[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
// search right point of segment in list
|
||
|
|
if( IsPointEqual(PointX2[i], PointY2[i], ResultPointX2[x-1], ResultPointY2[x-1]) ) { // x2,y2 = startpoint | x1,y1 = endpoint
|
||
|
|
ptfound = FOUND;
|
||
|
|
PointUsed[i] = USED;
|
||
|
|
ResultPointX1[x] = PointX2[i];
|
||
|
|
ResultPointY1[x] = PointY2[i];
|
||
|
|
ResultPointX2[x] = PointX1[i];
|
||
|
|
ResultPointY2[x] = PointY1[i];
|
||
|
|
ResultSegmentType[x] = SegmentType[i];
|
||
|
|
ResultSegmentWidth[x] = SegmentWidth[i];
|
||
|
|
ResultSegmentCurve[x] = SegmentCurve[i] * (-1); // swap also drawing direction of ARC (clockwise, counter-clockwise)
|
||
|
|
}
|
||
|
|
} // point used
|
||
|
|
// checked full array ?
|
||
|
|
if(i++ >= (NumSegments-1)) {
|
||
|
|
if(ptfound != FOUND) ptfound = ERROR;
|
||
|
|
}
|
||
|
|
} while(ptfound == NOT_FOUND);
|
||
|
|
// if point was not found -> end sorting of points
|
||
|
|
if (ptfound == ERROR) break;
|
||
|
|
} // for NumSegments
|
||
|
|
// count how many points are not used
|
||
|
|
int n;
|
||
|
|
int NumPointsUsed = 0;
|
||
|
|
for(i=0; i < NumSegments; i++) {
|
||
|
|
if(PointUsed[i] == USED) NumPointsUsed++;
|
||
|
|
}
|
||
|
|
// copy not used points to end of ResultPoint[]
|
||
|
|
for(i = NumSegments-1; i >= NumPointsUsed; i--) {
|
||
|
|
for(n = 0; n < NumSegments; n++) {
|
||
|
|
if(PointUsed[n] == NOT_USED) { // copy if point is not used
|
||
|
|
PointUsed[n] = USED;
|
||
|
|
ResultPointX1[i] = PointX1[n];
|
||
|
|
ResultPointY1[i] = PointY1[n];
|
||
|
|
ResultPointX2[i] = PointX2[n];
|
||
|
|
ResultPointY2[i] = PointY2[n];
|
||
|
|
ResultSegmentCurve[i] = SegmentCurve[n];
|
||
|
|
ResultSegmentType[i] = SegmentType[n];
|
||
|
|
ResultSegmentWidth[i] = SegmentWidth[n];
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// copy back sorted list
|
||
|
|
for(i=0; i<NumSegments; i++) {
|
||
|
|
PointX1[i] = ResultPointX1[i];
|
||
|
|
PointY1[i] = ResultPointY1[i];
|
||
|
|
PointX2[i] = ResultPointX2[i];
|
||
|
|
PointY2[i] = ResultPointY2[i];
|
||
|
|
SegmentType[i] = ResultSegmentType[i];
|
||
|
|
SegmentCurve[i] = ResultSegmentCurve[i];
|
||
|
|
SegmentWidth[i] = ResultSegmentWidth[i];
|
||
|
|
}
|
||
|
|
return NumSegments-NumPointsUsed; // return number of pending points
|
||
|
|
} // SortPointsEx
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void CloseOpenPolygon (void) {
|
||
|
|
int i, LineAdded;
|
||
|
|
int RemainingPoints, LastPoint;
|
||
|
|
do {
|
||
|
|
LineAdded = false;
|
||
|
|
RemainingPoints = SortPointsEx();
|
||
|
|
LastPoint = NumSegments - RemainingPoints - 1;
|
||
|
|
|
||
|
|
if(RemainingPoints) { // only search for gaps if remainingpoints != 0
|
||
|
|
for(i=LastPoint+1; i<NumSegments; i++) { // start from last+1 poly-segment -> search for points within circle
|
||
|
|
if(IsPointInCircle(PointX1[i], PointY1[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
|
||
|
|
PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
|
||
|
|
PointY1[NumSegments] = PointY2[LastPoint];
|
||
|
|
PointX2[NumSegments] = PointX1[i];
|
||
|
|
PointY2[NumSegments] = PointY1[i];
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
|
||
|
|
SegmentCurve[NumSegments++] = 0; // 2013-12-11
|
||
|
|
LineAdded = true;
|
||
|
|
break; // point within circle found and added -> escape from "for"-loop
|
||
|
|
}
|
||
|
|
if(IsPointInCircle(PointX2[i], PointY2[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
|
||
|
|
PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
|
||
|
|
PointY1[NumSegments] = PointY2[LastPoint];
|
||
|
|
PointX2[NumSegments] = PointX2[i];
|
||
|
|
PointY2[NumSegments] = PointY2[i];
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
|
||
|
|
SegmentCurve[NumSegments++] = 0; // 2013-12-11
|
||
|
|
LineAdded = true;
|
||
|
|
break; // point within circle found and added -> escape from "for"-loop
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} while(LineAdded); // resort points and close gaps if new line added
|
||
|
|
// finished correct -> but is polygon closed ?!? (firstpoint and lastpoint may no be the same coordinate !)
|
||
|
|
if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) { // poly closed ?
|
||
|
|
if(IsPointInCircle(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
|
||
|
|
PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
|
||
|
|
PointY1[NumSegments] = PointY2[LastPoint];
|
||
|
|
PointX2[NumSegments] = PointX1[0];
|
||
|
|
PointY2[NumSegments] = PointY1[0];
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
|
||
|
|
SegmentCurve[NumSegments++] = 0; // 2013-12-11
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int SortPoints(string ElementName) { // sort all points to a continous polygon
|
||
|
|
int LastPoint, RemainingPoints;
|
||
|
|
// close open polygon
|
||
|
|
if (CloseOpenPoly) CloseOpenPolygon();
|
||
|
|
// do final sorting
|
||
|
|
RemainingPoints = SortPointsEx();
|
||
|
|
// check if polygon is closed
|
||
|
|
LastPoint = NumSegments - RemainingPoints - 1;
|
||
|
|
if (LastPoint < 0) {
|
||
|
|
dlgMessageBox("!Negativ Index in function SortPoints().", "OK");
|
||
|
|
exit(-472);
|
||
|
|
}
|
||
|
|
if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) {
|
||
|
|
if(SegmentType[0] != CIRCLE) {
|
||
|
|
string x;
|
||
|
|
int pt_x, pt_y;
|
||
|
|
pt_x = PointX2[LastPoint];
|
||
|
|
pt_y = PointY2[LastPoint];
|
||
|
|
sprintf(x,"!%s contains an open polygon !\n\ncoordinate : X= %.6f[mm], Y= %.6f[mm]", ElementName, u2mm(pt_x), u2mm(pt_y));
|
||
|
|
if (dlgMessageBox(x, "OK", "Show") != 0) {
|
||
|
|
sprintf(x, "WIN (%.6fmm %.6fmm);\n", u2mm(pt_x), u2mm(pt_y));
|
||
|
|
exit(x);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return RemainingPoints;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_LibaryHeader(UL_BOARD BRD) { //-> create header of libary
|
||
|
|
int t = time();
|
||
|
|
string date;
|
||
|
|
string sourceID;
|
||
|
|
sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
|
||
|
|
sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE); // 2013-01-14
|
||
|
|
printf(".HEADER\n");
|
||
|
|
printf("LIBRARY_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
|
||
|
|
printf(".END_HEADER\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int CollectLibOutlineSegments(UL_ELEMENT E, int layer) { // get all segments of elements on 3D-layer
|
||
|
|
NumSegments=0;
|
||
|
|
E.package.circles(CIR) { // create circles
|
||
|
|
if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) {
|
||
|
|
PointX1[NumSegments] = CIR.x;
|
||
|
|
PointY1[NumSegments] = CIR.y;
|
||
|
|
PointX2[NumSegments] = CIR.x + CIR.radius;
|
||
|
|
PointY2[NumSegments] = CIR.y;
|
||
|
|
SegmentType[NumSegments] = CIRCLE;
|
||
|
|
SegmentWidth[NumSegments] = CIR.width;
|
||
|
|
SegmentCurve[NumSegments++] = 0; // 2013-12-11
|
||
|
|
}
|
||
|
|
}
|
||
|
|
E.package.wires(W) {
|
||
|
|
if(W.curve) { // create arcs
|
||
|
|
if(W.layer == layer && W.width > maxCutoutLineWidth) {
|
||
|
|
PointX1[NumSegments] = W.x1; // 2013-03-14 use wire coordinate, not arc!
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = ARC;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments++] = W.curve; //GetArcOptions(W);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else { // create straight lines
|
||
|
|
if(W.layer == layer && W.width > maxCutoutLineWidth) {
|
||
|
|
PointX1[NumSegments] = W.x1;
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments++] = 0; // 2013-12-11
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(NumSegments != 0) { // show warningbox if element contains no 3d-data
|
||
|
|
if(layer == bLayer3Ddata) { // is given layer the bottom layer -> mirror
|
||
|
|
for(int i=0; i<NumSegments; i++) { // swap x-coordinate for bottom parts
|
||
|
|
PointX1[i] = E.x - ((E.x - PointX1[i])*(-1));
|
||
|
|
PointX2[i] = E.x - ((E.x - PointX2[i])*(-1));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NumSegments;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_LibaryElectrical(UL_BOARD BRD) { //-> create electrical parts (R, C, IC, ...)
|
||
|
|
int i,x,inlib,NrOfPolygon;
|
||
|
|
int RemainingPoints;
|
||
|
|
string MountSide[] = {"TOP", "BOTTOM"};
|
||
|
|
int layer[] = { tLayer3Ddata, bLayer3Ddata };
|
||
|
|
|
||
|
|
for(i=0;i<NumParts;i++) {
|
||
|
|
BRD.elements(E) {
|
||
|
|
inlib = 0;
|
||
|
|
for(x=0; x<NumPacInLib; x++) { // check if new package
|
||
|
|
if(PacIn_LIB_name[x] == E.package.name &&
|
||
|
|
PacIn_LIB_angle[x] == E.angle &&
|
||
|
|
PacIn_LIB_Device_mountside[x] == E.mirror
|
||
|
|
) inlib = 1;
|
||
|
|
}
|
||
|
|
if(E.name == PartName[i] && inlib == 0) { // is package still in LIB-file
|
||
|
|
NrOfPolygon = 0;
|
||
|
|
if(DataOnLayerPresent(E, bLayer3Ddata)) NrOfPolygon=1; // if poly on bot-side found start from "1"
|
||
|
|
for(int tb=0;tb<2;tb++){
|
||
|
|
if(CollectLibOutlineSegments(E, layer[tb]) && SelectSide[tb]) { // only add package to lib if line-segments in layer found
|
||
|
|
do {
|
||
|
|
RemainingPoints = SortPoints(E.name); // returns number of open/not_used points
|
||
|
|
NumSegments -= RemainingPoints; // calculate nr of correct/used points in poly
|
||
|
|
// more than one outline in device present ?
|
||
|
|
if((NrOfPolygon == 0) && (RemainingPoints != 0)) NrOfPolygon=1;
|
||
|
|
printf(".ELECTRICAL\n");
|
||
|
|
printf("%s_ANGLE%.1f_%s.%d CI_LIB MM %.6f\n", E.package.name, E.angle, MountSide[tb], NrOfPolygon, getPartHeight());
|
||
|
|
OutputLines(E.x, E.y, OUTLINE); // add package to libfile -> subract given offsets -> E.x, E.y
|
||
|
|
printf(".END_ELECTRICAL\n");
|
||
|
|
CollectRemainingPoints(NumSegments, RemainingPoints);
|
||
|
|
PacIn_LIB_heights[NumPacInLib] = NrOfPolygon; // 0=package has only 1 poly; >0 package has more than one poly-outline
|
||
|
|
PacIn_LIB_name[NumPacInLib] = E.package.name; // mark that package is now in LIB-file
|
||
|
|
PacIn_LIB_Device_mountside[NumPacInLib] = E.mirror; // safe top- or bottom-side
|
||
|
|
PacIn_LIB_SubPart_mountside[NumPacInLib] = MountSide[tb]; // safe mountside of subparts
|
||
|
|
PacIn_LIB_angle[NumPacInLib++] = E.angle; // safe angle of partplacement
|
||
|
|
if(RemainingPoints != 0 || NrOfPolygon != 0) NrOfPolygon++;
|
||
|
|
} while(RemainingPoints != 0); // get multiple outline with multiple partheights
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_LibaryMechanical(UL_BOARD BRD) { //-> create mechanical parts (drills, holes, ...)
|
||
|
|
// not implemented yet
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
int CollectBoardOutlineSegments(UL_BOARD BRD) { //++ get all segments of boardoutline
|
||
|
|
NumSegments = 0;
|
||
|
|
// first search board outline in board direct
|
||
|
|
BRD.circles(CIR) {
|
||
|
|
if(CIR.layer == Layer3dBoardDimension) {
|
||
|
|
if (CIR.width > maxCutoutLineWidth) {
|
||
|
|
PointX1[NumSegments] = CIR.x;
|
||
|
|
PointY1[NumSegments] = CIR.y;
|
||
|
|
PointX2[NumSegments] = CIR.x + CIR.radius;
|
||
|
|
PointY2[NumSegments] = CIR.y;
|
||
|
|
SegmentType[NumSegments] = CIRCLE;
|
||
|
|
SegmentWidth[NumSegments] = CIR.width;
|
||
|
|
SegmentCurve[NumSegments++] = 0;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
CutoutPointX1[CutoutNumSegments] = CIR.x;
|
||
|
|
CutoutPointY1[CutoutNumSegments] = CIR.y;
|
||
|
|
CutoutPointX2[CutoutNumSegments] = CIR.x + CIR.radius;
|
||
|
|
CutoutPointY2[CutoutNumSegments] = CIR.y;
|
||
|
|
CutoutSegmentType[CutoutNumSegments] = CIRCLE;
|
||
|
|
CutoutSegmentWidth[CutoutNumSegments] = CIR.width;
|
||
|
|
CutoutSegmentCurve[CutoutNumSegments++] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
BRD.wires(W) {
|
||
|
|
if(W.layer == Layer3dBoardDimension) {
|
||
|
|
if (W.width > maxCutoutLineWidth) {
|
||
|
|
if(W.curve) { // create arcs board-outline board
|
||
|
|
PointX1[NumSegments] = W.x1; // 2013-03-14 use direct wire coordinate, not arc-coordinate
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = ARC;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W);
|
||
|
|
}
|
||
|
|
else { // create straight lines board-outline board
|
||
|
|
PointX1[NumSegments] = W.x1;
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments] = 0;
|
||
|
|
}
|
||
|
|
NumSegments++;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if(W.curve) { // create arcs board-outline board
|
||
|
|
CutoutPointX1[CutoutNumSegments] = W.x1;
|
||
|
|
CutoutPointY1[CutoutNumSegments] = W.y1;
|
||
|
|
CutoutPointX2[CutoutNumSegments] = W.x2;
|
||
|
|
CutoutPointY2[CutoutNumSegments] = W.y2;
|
||
|
|
CutoutSegmentType[CutoutNumSegments] = ARC;
|
||
|
|
CutoutSegmentWidth[CutoutNumSegments] = W.width;
|
||
|
|
CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
CutoutPointX1[CutoutNumSegments] = W.x1;
|
||
|
|
CutoutPointY1[CutoutNumSegments] = W.y1;
|
||
|
|
CutoutPointX2[CutoutNumSegments] = W.x2;
|
||
|
|
CutoutPointY2[CutoutNumSegments] = W.y2;
|
||
|
|
CutoutSegmentType[CutoutNumSegments] = LINE;
|
||
|
|
CutoutSegmentWidth[CutoutNumSegments] = W.width;
|
||
|
|
CutoutSegmentCurve[CutoutNumSegments] = 0;
|
||
|
|
}
|
||
|
|
CutoutNumSegments++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// second search board outline in packages
|
||
|
|
BRD.elements(E) {
|
||
|
|
E.package.circles(CIR) { // create board-outline of package-libary
|
||
|
|
if(CIR.layer == Layer3dBoardDimension) {
|
||
|
|
PointX1[NumSegments] = CIR.x;
|
||
|
|
PointY1[NumSegments] = CIR.y;
|
||
|
|
PointX2[NumSegments] = CIR.x + CIR.radius;
|
||
|
|
PointY2[NumSegments] = CIR.y;
|
||
|
|
SegmentType[NumSegments] = CIRCLE;
|
||
|
|
SegmentWidth[NumSegments] = CIR.width;
|
||
|
|
SegmentCurve[NumSegments++] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
BRD.elements(E) {
|
||
|
|
E.package.wires(W) {
|
||
|
|
if(W.layer == Layer3dBoardDimension) {
|
||
|
|
if (W.width > maxCutoutLineWidth) {
|
||
|
|
if(W.curve) { // create arcs board-outline of package-libary
|
||
|
|
PointX1[NumSegments] = W.x1;
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = ARC;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W);
|
||
|
|
}
|
||
|
|
else { // create straight lines board-outline of package-libary
|
||
|
|
PointX1[NumSegments] = W.x1;
|
||
|
|
PointY1[NumSegments] = W.y1;
|
||
|
|
PointX2[NumSegments] = W.x2;
|
||
|
|
PointY2[NumSegments] = W.y2;
|
||
|
|
SegmentType[NumSegments] = LINE;
|
||
|
|
SegmentWidth[NumSegments] = W.width;
|
||
|
|
SegmentCurve[NumSegments] = 0;
|
||
|
|
}
|
||
|
|
NumSegments++;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if(W.curve) { // create arcs board-cutout of package-libary
|
||
|
|
CutoutPointX1[CutoutNumSegments] = W.x1;
|
||
|
|
CutoutPointY1[CutoutNumSegments] = W.y1;
|
||
|
|
CutoutPointX2[CutoutNumSegments] = W.x2;
|
||
|
|
CutoutPointY2[CutoutNumSegments] = W.y2;
|
||
|
|
CutoutSegmentType[CutoutNumSegments] = ARC;
|
||
|
|
CutoutSegmentWidth[CutoutNumSegments] = W.width;
|
||
|
|
CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W);
|
||
|
|
}
|
||
|
|
else { // create line board-cutout of package-libary
|
||
|
|
CutoutPointX1[CutoutNumSegments] = W.x1;
|
||
|
|
CutoutPointY1[CutoutNumSegments] = W.y1;
|
||
|
|
CutoutPointX2[CutoutNumSegments] = W.x2;
|
||
|
|
CutoutPointY2[CutoutNumSegments] = W.y2;
|
||
|
|
CutoutSegmentType[CutoutNumSegments] = LINE;
|
||
|
|
CutoutSegmentWidth[CutoutNumSegments] = W.width;
|
||
|
|
CutoutSegmentCurve[CutoutNumSegments] = 0;
|
||
|
|
}
|
||
|
|
CutoutNumSegments++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(NumSegments == 0) {
|
||
|
|
string error;
|
||
|
|
sprintf(error,"!No board-outline on layer %d found !", Layer3dBoardDimension);
|
||
|
|
dlgMessageBox(error);
|
||
|
|
exit(-771);
|
||
|
|
}
|
||
|
|
return NumSegments;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_BoardHeader(UL_BOARD BRD) { //-## create header of boardfile
|
||
|
|
int t = time();
|
||
|
|
string date;
|
||
|
|
string sourceID;
|
||
|
|
|
||
|
|
sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
|
||
|
|
sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE);
|
||
|
|
printf(".HEADER\n");
|
||
|
|
printf("BOARD_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
|
||
|
|
printf("\"%s\" MM\n", filename(BRD.name));
|
||
|
|
printf(".END_HEADER\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_BoardOutline(UL_BOARD BRD) { //-## create outline of board
|
||
|
|
// get outline
|
||
|
|
CollectBoardOutlineSegments(BRD);
|
||
|
|
SortPoints("Board-Outline"); // boardname
|
||
|
|
// draw outline
|
||
|
|
printf(".BOARD_OUTLINE UNOWNED\n");
|
||
|
|
printf("%.6f\n", getPartHeight());
|
||
|
|
OutputBoardOutLines(0, 0, OUTLINE); // subract given offsets -> E.x, E.y
|
||
|
|
OutputBoardCutOutLines(0, 0, OUTLINE);
|
||
|
|
printf(".END_BOARD_OUTLINE\n");
|
||
|
|
LoopCounter = 0;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_BoardPlaceParts(UL_BOARD BRD) { //-## mount parts on board
|
||
|
|
int i, inlib;
|
||
|
|
string MountSide[] = {"TOP","BOTTOM"};
|
||
|
|
printf(".PLACEMENT\n");
|
||
|
|
BRD.elements(E) {
|
||
|
|
inlib = 0;
|
||
|
|
for(i=0; i<NumPacInLib; i++) { // check if elements was found in libary
|
||
|
|
if(PacIn_LIB_name[i] == E.package.name && PacIn_LIB_Device_mountside[i] == E.mirror && PacIn_LIB_angle[i] == E.angle) {
|
||
|
|
inlib = 1;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(inlib) { // only add part if part is in lib-file
|
||
|
|
if(PacIn_LIB_heights[i] == 0) { // part has only one height
|
||
|
|
printf("%s_ANGLE%.1f_%s.0 CI_LIB %s.0\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[i], E.name);
|
||
|
|
printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), MountSide[E.mirror]);
|
||
|
|
}
|
||
|
|
else { // part has multiple heights -> more than one part on same x/y position
|
||
|
|
int lib_start = i;
|
||
|
|
do {
|
||
|
|
printf("%s_ANGLE%.1f_%s.%d CI_LIB %s.%d\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[lib_start], PacIn_LIB_heights[lib_start], E.name, PacIn_LIB_heights[lib_start]);
|
||
|
|
printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), PacIn_LIB_SubPart_mountside[lib_start]);
|
||
|
|
lib_start++;
|
||
|
|
}while(PacIn_LIB_heights[lib_start] > 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
printf(".END_PLACEMENT\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_BoardHoles(UL_BOARD BRD) { //-## create holes in board (cutout, partholes, ...)
|
||
|
|
printf(".DRILLED_HOLES\n");
|
||
|
|
// drill holes from board direct
|
||
|
|
BRD.holes(H)
|
||
|
|
printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
|
||
|
|
// drill holes from elements
|
||
|
|
BRD.elements(E) {
|
||
|
|
E.package.holes(H)
|
||
|
|
printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
|
||
|
|
}
|
||
|
|
// drill pad(holes) from elements 2014-01-20
|
||
|
|
BRD.elements(E) {
|
||
|
|
E.package.contacts(C)
|
||
|
|
if (C.pad)
|
||
|
|
if (u2mm(C.pad.drill) > MinViaHoleDia)
|
||
|
|
printf("%.6f %.6f %.2f PTH BOARD Other UNOWNED\n", u2mm(C.pad.drill), u2mm(C.pad.x), u2mm(C.pad.y));
|
||
|
|
}
|
||
|
|
// drill big via's
|
||
|
|
BRD.signals(S) {
|
||
|
|
S.vias(V) {
|
||
|
|
if((DrillViaHoles == true) && (u2mm(V.drill) > MinViaHoleDia)) // drill via-hole
|
||
|
|
printf("%.6f %.6f %.6f PTH BOARD VIA UNOWNED\n", u2mm(V.drill), u2mm(V.x), u2mm(V.y));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
printf(".END_DRILLED_HOLES\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_CreateLibaryFile(UL_BOARD BRD, string fname) { // create libary for the IDF-board
|
||
|
|
output(fname, "wt") {
|
||
|
|
IDF_LibaryHeader(BRD);
|
||
|
|
IDF_LibaryElectrical(BRD);
|
||
|
|
IDF_LibaryMechanical(BRD);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void IDF_CreateBoardFile(UL_BOARD BRD, string fname) { // create boardfile with parts of libary
|
||
|
|
output(fname, "wt") {
|
||
|
|
IDF_BoardHeader(BRD);
|
||
|
|
IDF_BoardOutline(BRD);
|
||
|
|
IDF_BoardHoles(BRD);
|
||
|
|
IDF_BoardPlaceParts(BRD);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
void DisplayHelp(void) { // show helptext
|
||
|
|
dlgDialog("Generate 3D IDF data") {
|
||
|
|
dlgLabel("Version " + UlpVersion);
|
||
|
|
dlgHBoxLayout dlgSpacing(500);
|
||
|
|
dlgHBoxLayout {
|
||
|
|
dlgVBoxLayout dlgSpacing(200);
|
||
|
|
dlgTextView(usage);
|
||
|
|
}
|
||
|
|
dlgLabel(Docuemantpath);
|
||
|
|
dlgHBoxLayout {
|
||
|
|
dlgStretch(1);
|
||
|
|
dlgPushButton("-Back") dlgReject();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////
|
||
|
|
// S T A R T of U L P
|
||
|
|
//
|
||
|
|
if (board) {
|
||
|
|
int proceed = 0;
|
||
|
|
string FileDirectoryName;
|
||
|
|
string FilenamePanel;
|
||
|
|
string FileNameIDB; // Board
|
||
|
|
string FileNameIDL; // Library
|
||
|
|
board(BRD) {
|
||
|
|
FileDirectoryName = filedir(BRD.name);
|
||
|
|
FileNameIDB = filesetext(filename(BRD.name), ".IDB");
|
||
|
|
FileNameIDL = filesetext(filename(BRD.name), ".IDL");
|
||
|
|
}
|
||
|
|
dlgDialog("Generate 3D data format (IDF-file)") {
|
||
|
|
dlgHBoxLayout {
|
||
|
|
dlgGroup(" settings ") {
|
||
|
|
dlgGridLayout {
|
||
|
|
dlgCell(0,0) dlgCheckBox("close polygon if gap is smaller than : ", CloseOpenPoly);
|
||
|
|
dlgCell(0,1) dlgRealEdit(MaxGapWidth);
|
||
|
|
dlgCell(0,2) dlgLabel(" mm");
|
||
|
|
|
||
|
|
dlgCell(1,0) dlgCheckBox("drill via-holes if via is bigger than : ", DrillViaHoles);
|
||
|
|
dlgCell(1,1) dlgRealEdit(MinViaHoleDia);
|
||
|
|
dlgCell(1,2) dlgLabel(" mm");
|
||
|
|
|
||
|
|
dlgCell(2,0) dlgCheckBox("Export top parts", SelectSide[0]);
|
||
|
|
dlgCell(3,0) dlgCheckBox("Export bottom parts", SelectSide[1]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dlgGridLayout {
|
||
|
|
dlgCell(1,0) dlgLabel("Output Directory:");
|
||
|
|
dlgCell(1,1) dlgLabel(FileDirectoryName, 1);
|
||
|
|
dlgCell(1,2) {
|
||
|
|
dlgPushButton("Browse") {
|
||
|
|
string fdn = dlgDirectory("Save IDF file", FileDirectoryName);
|
||
|
|
if (fdn) {
|
||
|
|
int len = strlen(fdn);
|
||
|
|
if (fdn[len] != '/') fdn+="/"; // dlgDirectory gibt den Pfad ohne abschliessenden Slash zurück!
|
||
|
|
FileDirectoryName = fdn;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dlgCell(2,0) dlgLabel("Filename IDB (Board)");
|
||
|
|
dlgCell(2,1) dlgStringEdit(FileNameIDB);
|
||
|
|
dlgCell(2,2) {
|
||
|
|
dlgPushButton("Browse") {
|
||
|
|
string fdb = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDB)");
|
||
|
|
if (fdb) {
|
||
|
|
FileNameIDB = filename(fdb);
|
||
|
|
if(strchr(FileNameIDB, '.') < 0) // add fileextension if missing
|
||
|
|
FileNameIDB += ".IDB";
|
||
|
|
FileNameIDL = filesetext(FileNameIDB, ".IDL");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dlgCell(3,0) dlgLabel("Filename IDL (Library)");
|
||
|
|
dlgCell(3,1) dlgStringEdit(FileNameIDL);
|
||
|
|
dlgCell(3,2) {
|
||
|
|
dlgPushButton("Browse") {
|
||
|
|
string fdl = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDL)");
|
||
|
|
if (fdl) {
|
||
|
|
FileNameIDL = filename(fdl);
|
||
|
|
if(strchr(FileNameIDL, '.') < 0) // add fileextension if missing
|
||
|
|
FileNameIDL += ".IDL";
|
||
|
|
FileNameIDB = filesetext(FileNameIDL, ".IDB");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
dlgHBoxLayout {
|
||
|
|
dlgPushButton("OK") { proceed = 1; dlgAccept(); }
|
||
|
|
dlgPushButton("Cancel") dlgReject();
|
||
|
|
dlgStretch(1);
|
||
|
|
dlgLabel("Version: " + UlpVersion);
|
||
|
|
dlgPushButton("Help") DisplayHelp();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
if(proceed) {
|
||
|
|
project.board(BRD) {
|
||
|
|
CollectPartData(BRD); // read out data from BRD
|
||
|
|
IDF_CreateLibaryFile(BRD, FileNameIDL);
|
||
|
|
IDF_CreateBoardFile(BRD, FileNameIDB);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
dlgMessageBox(usage + "<hr><b>ERROR: No board!</b><p>\nThis program can only work in the layout editor.");
|
||
|
|
exit(0);
|
||
|
|
}
|