#usage "Ausgabe eines <b>Sch</b>altplanes als "
"<b>C</b>omputer <b>G</b>raphics <b>M</b>etafile "
"für bequemen Dokument-Import sowie String-Suchmöglichkeit in "
"daraus generierten PDFs.<p>\n"
"Ein entsprechendes Standard-Importfilter muss in Ihrer "
"Textverarbeitung (bspw. MS Office) installiert sein!<p>"
"Einzige bleibende Unzulänglichkeit sind Polygone mit Bogen-Begrenzung."
"<p><b>Kommandozeilenargument:</b> Dateiname (optional)<p><hr>"
"<author>Autor: <A href=mailto:henrik.haftmann@e-technik.tu-chemnitz.de>"
"henrik.haftmann@e-technik.tu-chemnitz.de</A>,<br>\n"
"URL: <A href='http://www.tu-chemnitz.de/~heha/hs_freeware/sch2cgm/'>"
"http://www.tu-chemnitz.de/~heha/hs_freeware/sch2cgm/</A>,<br>\n"
"Chemnitz, 7.10.05</author>"
// Mehr Features:
// Die Ausgabe erfolgt (im Bunt-Fall) lagenweise von hinten nach vorn.
// Deshalb ist es hiermit möglich, Schaltungsteile farblich zu hinterlegen
// (was in Eagle auf dem Bildschirm, nicht jedoch beim Drucken funktioniert)
// um eine bessere Schaltungsdokumentation zu erreichen.
// Zur Hinterlegung benutze man sehr helle Farben,
// für Schwarzweiß-Ausgabe eine Schraffur.
// Farb-Auswahl:
// Die im Dialog angegebene Hintergrundfarbe wird nicht im .CGM ausgegeben;
// das .CGM ist stets transparent (und ohne Hintergrundfarbe)
// Ist ein schwarzer Hintergrund gewünscht, muss die Grafik über
// eine schwarze Fläche positioniert werden.
// Könnte mal später noch ein Schalter werden... (bei Bedarf)
// Schrift-Ersetzung:
// "Arial fett" macht m. E. den besten Eindruck, für alle drei Eagle-Schriften.
// (Wer verwendet sie ernsthaft alle?)
// Schaltpläne im WWW:
// Ein brauchbares Vektorformat fürs WWW ist mir noch nicht über den
// Weg gelaufen (SWF?), hier muss man bei Pixelgrafik bleiben.
// Bewährt hat sich ein Export bei (nur) 100 dpi ins Clipboard,
// anschließend Reduktion auf 16 Farben und Speichern als .GIF oder .PNG.
// Getestet mit:
// Eagle 4.11 für Windows, Microsoft Office 2000 deutsch
int NumSheet; // Anzahl Seiten des Schaltplans
int NumHatched; // Anzahl Layer mit Füll-Stil<>1 (üblich: keine)
int NumFont[]; // Anzahl Vorkommen von Vektor/Prop/Fixed-Fonts
string SName; // Schaltplan-Name (ohne Pfad)
int col[]; // Farb-Indizes der (bis zu 256) Layer, 0 = unsichtbar
int fil[]; // Füll-Stile der (bis zu 256) Layer, 1 = gefüllt
// **** Dialog ****
// Voreinstellungen
int PaletteType=2; // Farbmodell, 2. Parameter für palette()
// PaletteType=0 bedeutet Schwarzweiß-Ausgabe (1 Layer)
int Filled=1; // Gestrichelt definierte Layer gefüllt (!Polygone)
int MakePolyline=0; // Zusammenfassung von Linienstücken zu PolyLine
// Rätselhafterweise ergibt MakePolyline auf dem Bildschirm fehlpositionierte
// Linien, sieht erschreckend hässlich aus!
// Deshalb nur für (kleine) PDFs und zum Ausdrucken verwenden!
int AllPages=0; // Automatisch alle Seiten generieren
int FontSel[]={1,1,0}; // ... ein Fall für eine Art INI-Datei
int FontBold[]={1,1,1};
int FontItalic[]={0,0,0};
string FontSrc[]={"Vektor","Proportional","Fixed"};
string FontSys[]={"Courier","Arial","Times"};
string FontLabel[];
void SetFontLabels(void) {
for (int idx=0; idx<3; idx++) {
string s=FontSrc[idx];
if (FontItalic[idx]) s="<i>"+s+"</i>";
if (FontBold[idx]) s="<b>"+s+"</b>";
sprintf(FontLabel[idx],"<font face=%s>%s</font>:",FontSys[FontSel[idx]],s);
}
}
void FontSubstLine(int idx) {
dlgCell(idx,0) {
dlgLabel(FontLabel[idx],1);
dlgSpacing(10);
}
dlgCell(idx,1) {
dlgComboBox(FontSys,FontSel[idx]) SetFontLabels();
dlgSpacing(10);
}
dlgCell(idx,2) dlgCheckBox("Fett",FontBold[idx]) SetFontLabels();
dlgCell(idx,3) dlgCheckBox("Kursiv",FontItalic[idx]) SetFontLabels();
}
int Dialog(void) {
status("Dialog");
return dlgDialog("CGM-Export-Optionen") {
dlgLabel("Dateiname: <b>"+SName+"</b>");
dlgGroup("Ausgabe-&Farben (siehe Eagle-Palette)") {
dlgRadioButton("&Schwarz auf Weiß (Schwarzweiß)",PaletteType);
dlgRadioButton("Bunt auf Schwarz",PaletteType);
dlgRadioButton("&Bunt auf Weiß (Standard)",PaletteType);
dlgRadioButton("Bunt auf farbigem Hintergrund",PaletteType);
}
dlgGroup("Schrift-&Ersetzung (verwendete Schriften gelistet)") dlgGridLayout{
SetFontLabels();
for (int i=0; i<3; i++) if (NumFont[i]) FontSubstLine(i);
}
if (NumHatched) dlgCheckBox("A&usgefüllt (schraffierte Layer)",Filled);
dlgCheckBox("P&olylinien generieren (statt einzelne Linien)",MakePolyline)
if (MakePolyline) dlgMessageBox(
"Die Bildschirmdarstellung der .CGM-Grafik wird fehlpositionierte "
"Linien anzeigen.\nBeim Drucken oder PDF-Export ist jedoch alles OK, "
"und die Ausgabedaten sind etwas kleiner.");
if (NumSheet>1) {
dlgSpacing(4);
dlgCheckBox("&Alle Seiten (mehrere Dateien »-nr.cgm«)",AllPages);
}
dlgSpacing(4);
dlgHBoxLayout {
dlgPushButton("+OK") dlgAccept(1);
dlgPushButton("Abbrechen") dlgReject();
dlgPushButton("Über...") dlgMessageBox(";"+usage);
}
};
}
/* Suche nach verwendeten Text-Fonts, für Dialog */
void CountFonts(UL_SCHEMATIC SC) {
SC.sheets(S){
string e;
sprintf(e,"Seite %d",S.number);
status(e);
NumSheet++;
S.busses(B) {
B.segments(SE) {
SE.texts(T) if (col[T.layer]) NumFont[T.font]++;
}
}
S.nets(N) {
N.segments(SE) {
SE.texts(T) if (col[T.layer]) NumFont[T.font]++;
}
}
S.parts(P) {
P.instances(I) {
I.gate.symbol.pins(P) {
P.texts(T) if (col[T.layer]) NumFont[T.font]++;
}
I.gate.symbol.texts(T) if (col[T.layer]) NumFont[T.font]++;
I.texts(T) if (col[T.layer]) NumFont[T.font]++;
}
}
S.texts(T) NumFont[T.font]++;
}
}
// **** globale Variablen ****
int MinColor=64,MaxColor; // zur Einschränkung der Farbpaletteneinträge
int CurLayer;
int InLine; // zur Verkettung von Line zu PolyLine
int LastX,LastY; // (kleinere Datei, schnelleres Rendern)
// Hier: zur sparsamen Ausgabe von Gerätekontextinformationen verwendet
int LineWidth;
int IntStyle; // 0=leer (Kreise!), 1=gefüllt (alles andere), 2=Hatch
int HatchIndex; // Füllmuster: 1 == 2 || 3 // 4 \\ 5 ++ 6 xx
int Color;
int TextAlign;
int EdgeVis; // 0 = AUS, 1 = EIN
int CharOri; // 0 = horizontal, 1 = vertikal
int LineStyle; // 1 = durchgehend, 2 = ---, 3 = ···, 4 = -·-·-
int CharHeight;
int Font;
/* Behandlung globaler Variablen */
void ResetDC(void) { // für jede neue Datei aufrufen
LineWidth=0;
IntStyle=-1;
HatchIndex=0;
Color=0;
TextAlign=-1;
EdgeVis=-1;
CharOri=0;
LineStyle=0;
CharHeight=-1;
Font=0;
}
int Hatch(int layer) {
return Filled?1:fil[layer];
}
void SetLineWidth(int n) {
if (LineWidth!=n) {
printf("linewidth %d;\n",n);
printf("edgewidth %d;\n",n);
LineWidth=n;
}
}
void SetLineStyle(int n) {
if (LineStyle!=n) {
printf("linetype %d;\n",n);
LineStyle=n;
}
}
void SetHatchIndex(int n) {
if (HatchIndex!=n) {
printf("hatchindex %d;\n",n);
HatchIndex=n;
}
}
void SetIntStyle(int n) {
string st[]={"EMPTY","SOLID","HATCH"};
int ha[]={0,0,1,3,3,4,4,5,6,6,6,6,5,5,5,5}; // etwa wie Eagle
int j=n; if (j>2) j=2;
if (IntStyle!=j) {
printf("intstyle %s;\n",st[j]);
IntStyle=j;
}
if (j==2) SetHatchIndex(ha[n]);
}
void SetEdgeVis(int n) {
if (EdgeVis!=n) {
printf("edgevis %s;\n",n?"ON":"OFF");
EdgeVis=n;
}
}
void SetTextAlign(int n) {
if (TextAlign!=n) {
string s1[]={"LEFT","RIGHT"};
string s2[]={"BASE","CAP"};
printf("textalign %s,%s;\n",s1[n&1],s2[n>>1]);
TextAlign=n;
}
}
void SetCharHeight(int n) {
if (CharHeight!=n) {
printf("charheight %d;\n",n);
CharHeight=n;
}
}
void SetCharOri(int n) {
if (CharOri!=n) {
string s[]={"(0,1200) (1200,0)","(-1200,0) (0,1200)"};
printf("charori %s;\n",s[n]);
CharOri=n;
}
}
void SetFont(int n) {
if (Font!=n) {
printf("textfontindex %d;\n",n);
Font=n;
}
}
int SetLayer(int n) {
int c=col[n]; // c=0 wenn Layer nicht sichtbar
if (c) {
if (Color!=c) {
printf("linecolr %d;\n",c);
printf("edgecolr %d;\n",c);
printf("fillcolr %d;\n",c);
printf("textcolr %d;\n",c);
}
Color=c;
}
return c;
}
string EscapeStr(string s) {
int j;
j=strchr(s,'\'');
if (j==-1) return s; // unverändert
string t;
int i=0;
do{
j++;
t+=strsub(s,i,j-i)+"'";
i=j;
j=strchr(s,'\'',i);
}while (j!=-1);
return t;
}
void EndLine(void) {
if (InLine) printf(";\n");
InLine=0;
}
int DontDraw(int layer) {
return PaletteType && layer!=CurLayer // Bunt: lagenweise
|| !PaletteType && !col[layer]; // Schwarzweiß: sichtbares
}
/* Abarbeitung von Eagle-Zeichenprimitiven */
void HandleCircle(UL_CIRCLE O) {
if (DontDraw(O.layer)) return;
EndLine();
SetLineStyle(1);
SetIntStyle(0);
SetEdgeVis(1);
SetLineWidth(O.width);
printf("circle (%d,%d) %d;\n",O.x,O.y,O.radius);
}
void HandleJunction(UL_JUNCTION O) {
if (DontDraw(LAYER_NETS)) return;
EndLine();
SetLineStyle(1);
SetIntStyle(1);
SetEdgeVis(1);
SetLineWidth(1524);
printf("circle (%d,%d) %d;\n",O.x,O.y,O.diameter/2);
}
void HandleText(UL_TEXT O) {
if (DontDraw(O.layer)) return;
EndLine();
SetFont(O.font+1);
SetCharHeight(O.size);
int i=O.angle/90+O.mirror*4; // Bit2=Mirror, Bit1:0=Drehung
int k[]={0,0,3,3,1,2,2,1}; // Zuordnungstabelle TextAlign
SetCharOri(i&1);
SetTextAlign(k[i]);
// printf("circle (%d,%d) %d;\n",T.x,T.y,10000);
printf("text (%d,%d) final '%s';\n",O.x,O.y,EscapeStr(O.value));
}
void HandlePolygon(UL_POLYGON O) {
if (DontDraw(O.layer)) return;
EndLine();
SetLineStyle(1);
SetIntStyle(O.pour==POLYGON_POUR_HATCH ? 7 : (Filled?1:fil[O.layer]));
SetEdgeVis(1);
SetLineWidth(O.width);
printf("polygon");
O.wires(W) {
printf(" (%d,%d)",W.x1,W.y1);
}
printf(";\n");
}
void HandleRectangle(UL_RECTANGLE O) {
if (DontDraw(O.layer)) return;
EndLine();
SetIntStyle(Filled?1:fil[O.layer]);
if (IntStyle==1) SetEdgeVis(0);
else{
SetEdgeVis(1);
SetLineWidth(0);
}
int l=O.x1,t=O.y1,r=O.x2,b=O.y2;
int i=O.angle/90;
if (i&1) { // 90° oder 270°
int x=(l+r)/2,y=(t+b)/2; // Dreh-Mitte
l=x+y-O.y1; // neue Ecken berechnen
t=y-x+O.x1;
r=x+y-O.y2;
b=y-x+O.x2;
}
printf("rect (%d,%d) (%d,%d);\n",l,t,r,b);
}
void HandleWire(UL_WIRE O) {
if (DontDraw(O.layer)) return;
int st;
switch (O.style) {
case WIRE_STYLE_CONTINUOUS: st=1; break;
case WIRE_STYLE_LONGDASH: st=2; break;
case WIRE_STYLE_SHORTDASH: st=3; break;
case WIRE_STYLE_DASHDOT: st=4; break;
}
if (st!=LineStyle || O.width!=LineWidth || O.arc) EndLine();
SetLineStyle(st);
SetLineWidth(O.width);
if (O.arc) {
printf("arcctr (%d,%d),(%d,%d),(%d,%d),%d;\n",
O.arc.xc,O.arc.yc,
O.arc.x1-O.arc.xc,O.arc.y1-O.arc.yc,
O.arc.x2-O.arc.xc,O.arc.y2-O.arc.yc,
O.arc.radius);
}else{
if (!InLine || O.x1!=LastX || O.y1!=LastY) {
EndLine();
printf("line (%d,%d)",O.x1,O.y1);
InLine=1;
}
printf(" (%d,%d)",O.x2,O.y2);
if (!MakePolyline) EndLine();
LastX=O.x2; LastY=O.y2;
}
}
/* Abarbeitung eines Layers (schwarzweiß: alle) */
/* Warum auch immer erscheinen die Elemente des Layers 93 (Pins) nicht */
void WalkLayer(UL_SHEET S) {
string e;
sprintf(e,"Seite %d Layer %d",S.number,CurLayer);
status(e);
S.busses(B) {
B.segments(SE) {
SE.texts(T) HandleText(T);
SE.wires(W) HandleWire(W);
}
}
S.circles(C) HandleCircle(C);
S.nets(N) {
N.segments(SE) {
SE.junctions(J) HandleJunction(J);
SE.texts(T) HandleText(T);
SE.wires(W) HandleWire(W);
}
}
S.parts(P) {
P.instances(I) {
I.gate.symbol.circles(C) HandleCircle(C);
I.gate.symbol.pins(P) {
P.circles(C) HandleCircle(C);
P.texts(T) HandleText(T);
P.wires(W) HandleWire(W);
}
I.gate.symbol.polygons(P) HandlePolygon(P);
I.gate.symbol.rectangles(R) HandleRectangle(R);
I.gate.symbol.texts(T) HandleText(T); // Unsmashed
I.gate.symbol.wires(W) HandleWire(W);
I.texts(T) HandleText(T); // Smashed
}
}
S.polygons(P) HandlePolygon(P);
S.rectangles(R) HandleRectangle(R);
S.texts(T) HandleText(T);
S.wires(W) HandleWire(W);
EndLine();
}
/* Abarbeitung layer-weise von hinten nach vorn */
void WalkLayers(UL_SHEET S) {
if (PaletteType) for (CurLayer=255; CurLayer>=0; CurLayer--) {
if (SetLayer(CurLayer)) WalkLayer(S);
}else WalkLayer(S);
}
string BuildFontName(int idx) { // .CGM-Schriftartenname generieren
int sel=FontSel[idx];
string r=sel==1?"Helvetica":FontSys[sel];
if (sel==2 || FontBold[idx] || FontItalic[idx]) r+="-";
if (sel==2 && !FontBold[idx] && !FontItalic[idx]) r+="Roman";
if (FontBold[idx]) r+="Bold";
if (FontItalic[idx]) r+=sel==2?"Italic":"Oblique";
return r;
}
/* Ausgabe einer Metadatei */
void PrintMF(UL_SHEET S) {
printf("BEGMF 'Schaltplan %s",filename(SName));
if (NumSheet>1) printf(" Seite %d/%d",S.number,NumSheet);
printf("';\n");
printf("mfversion 1;\n");
printf("mfelemlist 'DRAWINGPLUS';\n");
printf("vdctype integer;\n");
printf("fontlist '%s', '%s', '%s';\n",
BuildFontName(0),BuildFontName(1),BuildFontName(2));
printf("BEGMFDEFAULTS;\n");
printf(" vdcext (%d,%d) (%d,%d);\n",S.area.x1,S.area.y1,S.area.x2,S.area.y2);
printf(" clip off;\n");
if (PaletteType) {
int i,k,rgb;
printf(" colrmode indexed;\n");
printf(" colrtable %d\n",MinColor);
i=MaxColor; k=MinColor; do{
rgb=palette(k++,PaletteType-1);
printf(" %d %d %d%s\n",rgb>>16,rgb>>8&0xFF,rgb&0xFF,--i?"":";");
}while (i);
rgb=palette(0,PaletteType-1);
printf(" backcolr %d %d %d;\n",rgb>>16,rgb>>8&0xFF,rgb&0xFF);
}
printf(" linewidthmode abs;\n");
printf(" edgewidthmode abs;\n");
printf(" textprec stroke;\n");
printf(" transparency ON;\n");
printf("ENDMFDEFAULTS;\n");
printf("BEGPIC '%s';\n",SName);
printf("BEGPICBODY;\n");
// printf("linecap 3;\n"); // runde Enden, auch an Strichellinien
// printf("linejoin 3;\n"); // runde Ecken (keine Wirkung in Word)
ResetDC(); // globale Variablen in Ausgangsstellung
WalkLayers(S);
printf("ENDPIC;\n");
printf("ENDMF;\n");
}
/* Hauptprogramm */
if (schematic) {
string FName;
// Informationen über Schaltplan und Layer einsammeln
schematic(S) {
S.layers(L) if (L.visible) {
col[L.number]=L.color; // Layer vermerken
fil[L.number]=L.fill; // Füll-Stile (1 = komplett gefüllt)
if (L.fill!=1) NumHatched++;
MinColor=min(MinColor,L.color);
MaxColor=max(MaxColor,L.color);
}
FName=filesetext(S.name,".cgm");
SName=filename(S.name);
CountFonts(S);
}
// Nutzer-Dialog anzeigen (Kommandozeilen-Optionsauswertung fehlt noch)
if (Dialog()!=1) exit(0);
// Dateiname erfragen
if (argc < 2) {
FName=dlgFileSave("Speichern Computer Graphics Metafile",FName,"*.cgm");
}else{
FName=argv[1];
}
if (!FName) exit(0);
if (AllPages) {
schematic(S) S.sheets(SH) {
string e;
sprintf(e,"-%d%s",SH.number,fileext(FName));
output(filesetext(FName,e),"wb") PrintMF(SH);
}
}else{
sheet(S) output(FName,"wb") PrintMF(S);
}
}else{
dlgMessageBox("Muss aus Schaltplan gestartet werden! Nur für Schaltpläne!", "OK");
}
Vorgefundene Kodierung: UTF-8 | 0
|