#usage "Ausgabe eines Schaltplanes als " "Computer Graphics Metafile " "für bequemen Dokument-Import sowie String-Suchmöglichkeit in " "daraus generierten PDFs.

\n" "Ein entsprechendes Standard-Importfilter muss in Ihrer " "Textverarbeitung (bspw. MS Office) installiert sein!

" "Einzige bleibende Unzulänglichkeit sind Polygone mit Bogen-Begrenzung." "

Kommandozeilenargument: Dateiname (optional)


" "Autor: " "henrik.haftmann@e-technik.tu-chemnitz.de,
\n" "URL: " "http://www.tu-chemnitz.de/~heha/hs_freeware/sch2cgm/,
\n" "Chemnitz, 7.10.05
" // 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=""+s+""; if (FontBold[idx]) s=""+s+""; sprintf(FontLabel[idx],"%s:",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: "+SName+""); 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"); }