Gibt es für tkinter Vektorgrafik Bibliotheken?

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Jerch Ja wenn man statt tkinter Vektorfgrafik eine andere Vektorgrafik macht, etwa so etwas wie tkzinc, läßt sich das Format importieren. Wenn es aber tkinter Vektorgrafik bleiben soll, dann gehen eben keine durchsichtigen Löcher auf einfache Art. Es sei denn, man flickt dann einen Schweizer Käse aus Einzelteilen so zusammen, dass dann dazwischen Löcher bleiben. Oder man biegt ein Hufeisen in eine Ringform, wenn es ein Ring sein soll.

Aber warum sollte ich mir so etwas antun, so etwas zusammenprogrammieren zu wollen? Konvertierung mit etwas zusätzlichem manuellen Aufwand ist bei vielen SVG Vektorgrafiken möglich. Das haben wir herausgefunden.

Will jemand das Thema weiter verfolgen? Soll man über eine Vektorgrafik Library nachdenken? Ob da die Grafiken aus SVG kommen oder nicht, kann sein oder auch nicht oder auch bunt gemischt.

Nochmal ein nettes Beispiel aus SVG. Das ließe sich automatisch konvertieren. Ob man smooth setzt oder nicht und wobei oder nicht, sollte man allerdings entscheiden. Hier war smooth generell gut:

Code: Alles auswählen

import tkinter as tk
 
class Curve(object):
    def __init__(self, x,y, precision=30):
        self.coordinates = [x,y]
        self.precision = precision
 
    def __iter__(self):
        return iter(self.coordinates)
 
    def line_to(self, *coords):
        self.coordinates.extend(coords)
 
    def becier(self, *coords):
        coords = iter(coords)
        px0, py0 = self.coordinates[-2:]
        for px1, py1, px2, py2, px3, py3 in zip(*[coords]*6):
            # B(t) = (1-t)^3 * P0  + 3t * (1-t)^2 * P1 + 3 t^2 * (1-t) * P2 + t^3 * P3
            for T in range(1,self.precision-1):
                t = T/self.precision
                Bx = (1-t)*(1-t)*(1-t)*px0 + 3*t*(1-t)*(1-t)*px1+3*t*t*(1-t)*px2+t*t*t*px3
                By = (1-t)*(1-t)*(1-t)*py0 + 3*t*(1-t)*(1-t)*py1+3*t*t*(1-t)*py2+t*t*t*py3
                self.coordinates.extend((Bx, By))
            px0, py0 = px3, py3
            self.coordinates.extend((px0,py0))

def main():

    root = tk.Tk()
    canvas = tk.Canvas(root,width=400,height=350)
    canvas.pack()
 
    scale = 0.03

    c = Curve(6993,5862)
    c.becier(4946,5697,4904,8018,3685,8018,2639,8018,2755,6895,2810,6574,2931,6565,3092,6521,3290,6397,3819,6065,3498,5420,3498,5420,3488,5646,3188,5666,3188,5666,2628,5693,2564,6131,2546,6365,2472,6191,2296,5873,2004,5900,1609,5936,1691,6093,1268,5875,1268,5875,1202,6505,1857,6665,2027,6707,2162,6705,2266,6683,2227,10048,5458,10817,7447,9970,9739,8994,9039,6026,6993,5862)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(7032,5479)
    c.becier(7097,5345,7551,4413,8384,4628,10223,5103,9898,2685,8448,3059,7312,3351,6970,5400,6942,5584,6942,5584,6939,5609,6949,5614,6988,5635,7032,5479,7032,5479)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6969,4281)
    c.becier(7050,3944,6639,1184,8227,1598,9030,1807,8820,3057,8000,3086,7230,3112,7168,3950,7046,4274,7046,4274,7030,4327,7000,4324,7000,4324,6960,4321,6969,4281)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6892,5586)
    c.becier(6892,5586,7148,44,4249,1229,4249,1229,2910,1850,3749,3232,4078,3774,4834,3773,5395,3673,5395,3673,5875,3568,6197,3953,6520,4338,6763,5492,6807,5578,6856,5674,6892,5586,6892,5586)
    canvas.create_polygon(*c,tags="img", fill='#64c3a3',smooth=1)

    c = Curve(6910,7636)
    c.becier(7003,7765,7143,7800,7223,7714,7302,7629,7290,7455,7197,7327,7104,7198,6964,7163,6885,7249,6806,7334,6817,7508,6910,7636)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(8373,9170)
    c.becier(8373,9170,7274,9561,6985,8468,6985,8468,6965,8432,6991,8413,7023,8389,7071,8417,7071,8417,7324,9482,8348,9080,8348,9080,8348,9080,8397,9091,8405,9110,8413,9129,8404,9166,8373,9170)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(7032,5479)
    c.becier(7097,5345,7551,4413,8384,4628,10223,5103,9898,2685,8448,3059,7312,3351,6970,5400,6942,5584,6942,5584,6939,5609,6949,5614,6988,5635,7032,5479,7032,5479)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)

    c = Curve(6892,5586)
    c.becier(6892,5586,7148,44,4249,1229,4249,1229,2910,1850,3749,3232,4078,3774,4834,3773,5395,3673,5395,3673,5875,3568,6197,3953,6520,4338,6763,5492,6807,5578,6856,5674,6892,5586,6892,5586)
    canvas.create_polygon(*c,tags="img", fill='#085877',smooth=1)
    
    canvas.scale("img",0,0,scale,scale)
 
    root.mainloop()
 
if __name__ == '__main__':
    main()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: Nochmal anschaulich. Statt irgendetwas umzusortieren oder drüberzumalen, mußt Du das "Polygon mit Loch" in zwei Polygone ohne Loch aufteilen:
...
6. Zeichen die Polygone.
Ja natürlich kann man das machen. Es gibt drei Möglichkeiten für so etwas:

Bild

Man begnügt sich beim Freiraum zwischen Ohr und Rüssel mit Canvas Background Farbe.
Wenn sagt sich, nein diese Grafik nehme ich nicht, denn Background Farbe stört, wenn man den Elefant verschiebt über etwas anderes.
Man ist ganz versessen darauf und will das unbedingt mit Loch haben. Dann kann man den Elefant nochmals nachzeichnen mit einem geeigneten Grafik Programm ohne das linke Ohr, sodass man den Freiraum hat und das linke Ohr kann man ja dann dransetzen.

Dann kommt es nur noch darauf an, wie das Grafikprogamm das speichert. Arbeitet es in Layers, die man bestimmen kann, oder speichert es das, wie es zuvor schon war, nämlich wieder mit herausgeschnittenem Loch?
Sirius3
User
Beiträge: 18294
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: würdest Du endlich mal die Dokumentation lesen, statt nur herumzuraten, wüßtest Du, dass smooth auch nichts anderes macht, als Du mit Deiner bezier-Methode. Nur dass TK die Kontrollpunkte rät und damit immer etwas anderes macht als beabsichtigt.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Alfons:
Deine Aufzählung ist witzig, hat aber leider rein gar nichts mit einer sinnvollen und strukturierten Annäherung an das Problem zu tun. Weiter oben fielen schonmal die Stichwörter "mathematische Grundlagen" und Spezifikation. Das wären vllt. geeignetere Startpositionen. Dein derzeitiges Stochern im "Wie könnte das gehen" erinnert eher an das blinde Huhn auf der Suche nach dem Korn.
Alfons Mittelmeyer hat geschrieben:... Aber warum sollte ich mir so etwas antun, so etwas zusammenprogrammieren zu wollen? ...]
Das frage ich mich allerdings auch.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Wenn ich ein Objekt habe, das aus Rundungen besteht, kann ich bei einer Becierkurve, wenn es nicht gut kommt, die Precision erhöhen. Wenn ein Objekt aus 100 Punkten mit smooth gut kommt, während ich bei einer hohen Precision 1000 Punkte brauche, dann brauche ich mehr Platz zum Abspeichern oder mehr Berechnungszeit, wenn ich es rotieren lassen will. Warum soll ich dann nicht bei geeigneten Polygonen smooth nehmen?

Ich will es ja nicht im Regelfall nehmen. Aber warum nicht dort, wo es vorteilhaft ist?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Das Problem ist doch längst gelöst. Nämlich Übernahme von geeigneten SVG Grafiken nach tkinter mit einfachen Mitteln. Einen Renderer schreiben habe ich keineswegs im Sinn. Man könnte etwa statt von einem Polygon von einer geschlossenen Polyline ausgehen und von dort aus nach innen den Raum mit Polygonen füllen, wobei bereits darin befindlich als geschlossene Polyline markierte Löcher ausgespart werden.

Solche mathematischen Lösungen sind jederzeit machbar, nur habe ich so etwas nicht im Sinn. Wozu auch? Wenn jemand gerne so etwas tun möchte, etwa Du jerch, dann tue Dir keinen Zwang an.

Also offensichtlich gibt es noch keine Vektor Grafik Bibliotheken für tkinter, aber man braucht für Vektor Grafik Bibliotheken für tkinter nicht alles neu zeichnen, sondern kann SVG Grafiken übernehmen. Das ist das Ergebnis dieses Threads.
Sirius3
User
Beiträge: 18294
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: was meinst Du jetzt schon wieder mit "Vektorgraphikbibliothek"? Canvas hat ein paar Zeichenprimitive, dass es keine Graphikprogramme gibt, die das explizit Exportieren können, liegt zum einen daran, dass sie in der landläufigen Bedeutung tatsächlich ziemlich primitiv sind, zum anderen, dass niemand bisher den Bedarf hatte, mit Canvas Zootiere darzustellen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Es geht nicht darum, aus tkinter ein Zeichenprogramm zu machen, wie etwa LibreOffice Draw, das aber zum Zeichnen auch nicht besonders viel bietet. Also, so etwas wäre schon möglich. Libre Office Draw kann aber verschiedene Formate lesen und exportieren. tkinter bietet nur postscript rendering für die Druckausgabe. Ein vernünftiges Format zum Datenaustausch wäre nicht schlecht.

Vielmehr geht es um ansprechende GUI. Professionelle Programme verwenden zur schönen Gestaltung Grafiken. Der Vorteil skalierbarer Grafiken ist, dass man sie nicht erst mit einem Bildbearbeitungsprogramm wie Gimp auf die gewünschte Größe skalieren muss, sondern man kann die Skalierung an Ort und Stelle vornehmen.

Außerdem, wenn Images klein sind, dann muss man sie so nehmen wie sie sind, denn Skaliereung bringt da nur verschlechterte Darstellung.

Und unter einer Vektorgrafikbibliothek stelle ich mir Files vor, die eine Sammlung von Vektorgrafiken beinhalten. Folgende Funktionen sollen dabei zur Verfügung stehen:

- Name der Sammlung
- Kurzbeschreibung
- Anzahl der Objekte
- Liste der Objekte (tags)
- abfragbar xmin,ymin,xmax,ymax pro Objekt
- Objekt laden in gewünschter Höhe an gewünsche Position in einen Canvas

Nice to Have:
- Objekte aus der Sammlung löschen
- Objekte aus einem Canvas in der Sammlung speichern

Außerdem:
- Übersicht der Objekte in Miniaturansicht mit Namen (tag)
- sowie auch Großansicht einzelner Objekte

PS: Dass man Zootiere verwenden soll für seine GUI, davon war nicht die Rede.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Das kennst Du oder? Zumindest kann der Vorgänger tkpath laut Screenshot/Beschreibung auch Löcher mittels evenodd malen. Einen separaten Download scheint es nicht zu geben, wahrscheinlich versteckt sich der Rohdiamant im Applikationscode.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Dass man ein Loch ausschneidet bzw. eine Fläche füllt, die auch nach innen eine Begrenzung hat, ist ganz normal. Das kann auch jeder Plotter und sollte auch jedes Grafikprogramm können. Tk gibt es seit 1991, da wundert man sich doch sehr, was es bis heute noch alles nicht kann. Schläft man da? Und auch dass man nur nach Postscript rendern kann, ist ein Witz. Grundlegende Funktionen, die man sich ja auch leicht selber implementieren kann, wie etwa Drehen werden nicht angeboten.

Eventuell würde tk ja sogar solche Löcher beherrschen. Wenn Du mein Pentagrammbeispiel angesehen hast, dann siehst Du dass es innen ein Loch hat. Das zeigt, dass tk nach der evenodd Regel füllt.

Eventuell scheitert es nur daran: dass ein Item hinter einem anderen ist, kann man angeben, dass es vor einem anderen ist, kann man auch angeben, aber dass es auf gleicher Ebene im gleichen Layer ist, kann man nicht angeben und damit auch nicht machen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
"Man" schläft da nicht, es gibt "man" einfach nicht. Tcl/Tk ist eine absolute Nische mit sehr wenig Manpower. Tk fehlt es an vielen sinnvollen Widgettypen und Abstraktionen, einfach weil es keiner gemacht hat.

Nebenbemerkung:
Deine Ausführungen sind immer voll von Deinen Annahmen, die Du als absolute Wahrheiten hinstellst. Das ist irritierend und kann Anfängern auf falsche Fährten bringen. Das solltest Du ändern. Wenn Du konkrete Fragen hast, ist es für alle einfacher, diese klar und präzise zu stellen anstatt sie in ellenlanges Geschwurbel mit falschen Absoluta zu verpacken. Das macht das Antworten sehr schwierig.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: würdest Du endlich mal die Dokumentation lesen, statt nur herumzuraten, wüßtest Du, dass smooth auch nichts anderes macht, als Du mit Deiner bezier-Methode. Nur dass TK die Kontrollpunkte rät und damit immer etwas anderes macht als beabsichtigt.
Wie bereits an anderer Stelle geschrieben, ist smooth nicht schlecht, weil man da nicht eine große Anzahl genau berechneter Punkte braucht. In bestimmten Fällen wird es ungenau.

Hier sieht man, warum der smooth bei dem Vogel nicht geklappt hatte:

Bild

Zweimal geladen mit dem GuiDesigner mit einer Höhe von 200. Der rechte Vogel wurde gespiegelt durch ein canvas.scale mit Scale Faktoren -1,1.
Und dann mit der Maus den dunklen Schnabel heruntergezogen.

Darunter sieht man, dass auch bereits beim Rumpf der Schnabel gezeichnet worden war. Wenn man den Rumpf smoothed, verändert der untere Schnabel seine Form und wird nicht mehr richtig durch den oberen Schnabelteil überdeckt. Daher darf man hier den Rumpf nicht smoothen.
Sirius3
User
Beiträge: 18294
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: wie bereits geschrieben, smooth macht immer Fehler und ist deshalb hier nie sinnvoll.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius
@Alfons Mittelmeyer: wie bereits geschrieben, smooth macht immer Fehler und ist deshalb hier nie sinnvoll.

Hier sind zwei Unworte drin, die man nicht benützen soll, nämlich immer und nie. Und wenn jemand solche Worte schreibt, ist davon auszugehen, dass die Aussage falsch ist.

Eine Kurve zu beschreiben durch Punkte, durch welche eine Gerade geht ist nämlich ein Fehler und wird bei stärkerer Vergrößerung sehr ungenau. Daher sollte eine Kurve durch eine Kurve beschrieben werden.

Und eine Kurve beschreiben macht man in tkinter durch Splines. Hier ist es aber unter den gegebenen Voraussetzungen nicht sinnvoll (also auch nicht nie). Und die gegebenen Vorraussetzungen sind, dass wir hier einen Pfad haben, der aus einer Kurvenform und einer Geradenform (Schnabel) besteht. Und wenn wir kein geeignetes Grafikumberechnungsprogramm haben, welches den Schnabel gesondert darstellt oder den unteren Teil beseitigt, können wir leider keine Splines zur Beschreibung der Kurvenform nehmen.
Sirius3
User
Beiträge: 18294
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: das sind keine Unwörter sondern die Mathematisch korrekte Wahrscheinlichkeitsangabe, dass jede nicht-triviale (nur aus einem Geradenstück bestehend) Kurve mit n Stützstellen und (n-1)*2 Kontrollpunkten wie sie bei SVG definiert sind, nicht durch eine äquivalente smooth-Kurve mit k Stützstellen wie sie bei TK definiert sind, darstellen läßt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 um exakte Nachbildung einer Bezierkurve geht es nicht. Es geht darum, ob sich durch Splinen Rundungen besser darstellen lassen als lediglich durch ein Vieleck.

Und wer schreibt, dass der Effekt von smooth unvorhersehbar sei, verbaut sich jeden Weg etwas erkennen zu können. Außerdem muss eine solche Aussage von Dir erst mal übersetzt werden, was sie eigentlich nur aussagt: Du hast lediglich keine Ahnung davon, wie sich smooth von tkinter verhält.

Und wie verhält sich smooth? Hier zu sehen: außen rot der Kreis, darin blau das Vieleck, darin schwaz mit smooth:

Bild
Sirius3
User
Beiträge: 18294
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: wer schreibt hier, dass etwas unvorhersehbar ist. Du gehst wieder einmal nur phänomenologisch an das Problem heran, obwohl es eine klare mathematische Beschreibung gibt. Die Tk-Dokumentation schreibt ja selbst, dass bei smooth jedes Segment des Polygons in 10 aufgespalten werden. Man hat aber keinen Einfluß auf die Kontrollpunkte. Damit ist es weniger mächtig als Kurven von SVG.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Also wörtlich 'unvorhersehber' hattest Du nicht geschrieben aber so ähnlich:
Nur dass TK die Kontrollpunkte rät und damit immer etwas anderes macht als beabsichtigt.
Es macht überhaupt nichts anderes als beabsichtigt:

gelb ist der Kreis, blau das Sechseck. Sechseck mit smooth und Radius multipliziert mit 2/sqtr(3) ergibt schwarzen Kreis (von Sechsecksplines) auf gelbem echtem Kreis (Oval):

Bild

Damit wären dann auch einfach möglich etwa schiefe Ellipsen (mit wenigen Punkten zur Beschreibung)
BlackJack

@Alfons Mittelmeyer: Wenn man etwas mit smooth macht und danach dann behauptet das wäre genau das was man beabsichtigt hatte, dann macht es natürlich das was man beabsichtigt. Man darf halt nur nichts beabsichtigen was nicht geht, also zum Beispiel den Vogel zeichnen. Nette ”Argumentation” die Du da gerade versuchst. :lol:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Mit smooth kann man Rundungen machen, mit geraden Linien spitze Ecken. Dass sich smooth nicht besonderes für spitze Ecken eignet versteht sich, es sei denn, man löst fein auf, wie man auch fein auflösen muss, wenn man mit geraden Linien Rundungen zeichnen will.

Bei SVG kann man Rundungen und gerade Linien in einem Pfad mischen, bei tkinter nicht. Aber warum sollen wir uns deshalb nicht weiter damit beschäftigen, was man mit smooth tun kann?

Man kann bei tkinter doch Rundungen und gerade Linien mischen:
-smooth boolean
Boolean must have one of the forms accepted by Tcl_GetBoolean. It indicates whether or not the polygon should be drawn with a curved perimeter. If so, the outline of the polygon becomes a set of parabolic splines, one spline for the first and second line segments, one for the second and third, and so on. Straight-line segments can be generated in a smoothed polygon by duplicating the end-points of the desired line segment.
Quelle: https://www.tcl.tk/man/tcl8.4/TkCmd/canvas.htm#M144
Antworten