[OOP Problem] Bibliothek mit Diagrammen? Bewertung des selbst erstellten

  • Guten Morgen und Danke für deine Erklärung und die Geduld mit mir 🙂


    So ich habe dich beim Wort genommen und das aufgezeichnet um zu sehen wo ich bei der Berechnung dann raus komme. Wenn man bei den Pixel auch von 0 mit zählen beginnt, dann bin ich mit dem Ergebnis einig:

    Heißt das jetzt für mich, das ich ein eindimensionales Array mache mit den Werten 0-20479 , da mein Display 160x128 Pixel hat, und dieses Array weise ich dann ‚data‘ aus dem Beispiel zu? Der jeweilige Index berechne ich, wie gezeigt.


    Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Das ist ein Weg. So gehe ich in meinem Code vor - ich veraendere alle Pixel in einem Buffer (auch ich habe verschiedene Dinge, die sich selbst darstellen). Und dann am Ende schreibe ich das alles in einem Rutsch weg.


    Es ist aber bereits eine Menge von Daten, die meinem S2 an die Grenze bringt. Also ist ggf. ein Vorgehen, sich beim malen auf einen Teilbereich (der ja auswaehlbar ist anhand seiner Koordinaten), die bessere Wahl.


    Und das wuerde ich in deinem Fall auch erstmal machen. Probier erstmal nur einen kleinen Auschnitt (8x8 oder so Pixel) irgendwo zu manipulieren. Vergiss dabei deine Design-Klasse, du musst erstmal wirklich verstehen, wie die API da arbeitet. Und da kommt dann auch die Frage des Datentypes und der Byte-Swaps rein. Ich nehme mal stark an, dass dein Display so wie meines 16 Bit / Pixel benutzt. Du musst also als Array-Datentyp "H" nehmen. Und dann mal einfarbige Rechtecke bauen, und schauen, was da wie funktioniert. Schau dir auch den Code des Moduls an, was das macht, um Pixel zu setzen.

  • Hallo,


    Danke für die Erklärung. Ja mein Display hat auch 16Bit.


    Ich versuche gerade dein Beispiel mit den 8x8 Pixel umzusetzen. Dabei will ich oben links ein Quadrat erstellen, also der Start ist bei x=0 und y=0.

    Ein Array mit dem Datentyp 'H' habe ich erstellt und die vier Eckpunkte habe ich auch berechnet. Zur Kontrolle hatte ich das Quadrat aufgezeichnet und beschriftet.


    Das habe ich so gemacht:

    Python
    def array():    
        x0 = (0 * WIDTH) + 0 
        x1 = (0 * WIDTH) +  7
        y0 = (7 * WIDTH) + 0
        y1 = (7 * WIDTH) + 7
        memory = uarray.array('H')
        pixel = list(range(16))
        for pixel in pixel: memory.append(pixel)

    Um ein Pixel zu setzen wird die Position des Pixels benötigt, x- und y sowie die Farbe. Im Vergleich zu der 'image'-Funktion benötigt Pixel keine Angabe nach major-row, sondern die Pixelposition kann beginnend von 0 angegeben werden. Mein Rechteck von 8x8 Pixel male ich so:


    Ich hoffe verstanden zu haben, wie man Pixel setzt und auch wie das Array aufgebaut sein muss.


    Aber ich sehe den Zusammenhang zu 'image' für den Buffer nicht. Diese Funktion erwartet die berechneten x0, y0,x1,y1 und das erstellte Array. Sollte ich nicht irgendwo noch angeben müssen, was an dieser Position gemalt werden soll? Zum Beispiel mein Rechteck.


    Habe ich das soweit richtig verstanden?


    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Ein Array hat schon alle Element, die es braucht, wenn du es richtig mit array(Typ, Größe) anlegst.


    Da muss nichts angehangen werden.


    Dann greifst du mit memory[position] drauf zu.


    Und der Inhalt deines arrays ist doch, was gemalt wird. Das ist doch der ganze Sinn der Übung. Es ist ein Buffer mit Pixel Daten, und die kannst du vorher eben setzten.


    memory = uarray.array('H', [0xff00ff for _ in range(16)])


    Und das jetzt einfach an einer Stelle malen.

  • Ich habe jetzt erst verstanden, zu was das Array gebraucht wird. Das Array ist der Buffer :wallbash: Oh man ich habe mich total auf das 'image' versteift und habe versucht herauszufinden, wie diese Funktion das Buffering übernimmt. Dabei werden meine Pixel im Array geladen (Buffering) und dann wird mit 'image' alle Pixel auf einmal auf den Bildschirm geschrieben, ja?


    Ich bekomme auch tatsächlich ein Quadrat auf mein Display :bravo2:

    Aber nicht wie gewünscht oder erwartet. Also ich habe 8x8 Pixel ausgewählt, dann sieht mein Bereich so aus:

    Meine Eckpunkte sind 0, 7, 56 und 63.

    Das sind meine x0, x1, y0 und y1 die ich auch berechnet habe.

    Dann zeichne ich mein Quadrat so:


    Code
        memory = uarray.array('H', [0xff00ff for _ in range(64)])
        tft.image(0, 56, 7, 63, memory)

    Und das Ergebnis sieht so aus:

    Es ist da, nur ist 0 nicht gleich meiner 0. Beginnt man nicht in einer Ecke zu zählen oder kommt jetzt das mit dem Byte-swappen?

    Es ist egal wie ich die Rotation des Displays ändere, das Quadrat ist nie in der Ecke des Displays.


    Aber es kommt auf einen Schlag :love:

    VIelen Dank für deine Gedult und Mühe @__deets__ !


    Das ist ja wie ein Privater Einstiegskurs den du mir hier gibst. :)


    Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

    Edited 2 times, last by Dennis89: Erste Bearbeitung war falsch, wurde wieder gelöscht ().

  • Du hast hier immer noch ein Missverstaendnis. Es geht nicht (und ging nie) um die Werte der Eckpunkt in deinem array. Es gebt darum darzustellen, wie eine zweidimensionale Struktur auf ein eindimensionales Array abgebildet wird.


    Damit definierst du ein 8x8 Pixel grosses Bild, und mit der Berechnungsvorschrift (row-major) bestimmst du IN DIESEM AUSSCHNITT, wie du einen Pixel an Stelle x/y dann tatsaechlich setzt.


    Und dann bringst du dieses Rechteck auf das Display. Das ist darauf vorbereitet, und da ist der call fuer da - du weisst, dass du ein 8x8 Pixel grossen Auschnitt kopieren willst. Und mit den Koordinaten gibst du an, wo genau du diese Briefmarke auf deinem grossen Kuvert hinpappen willst.


    Code
      def image( self, x0, y0, x1, y1, data ) :
        self._setwindowloc((x0, y0), (x1, y1))
        self._writedata(data)

    x0, y0 gibt also die obere linke Ecke an, und x1, y1 die untere Rechte, in welche dein buffer kopiert werden soll. Dass muss also


    (0, 0), (7, 7) (ggf. auch (8, 8), je nachdem ob das inklusive oder exlusive ist) sein.

  • Okay, vielen Danke für die weitere Erklärung :)


    Ich werde damit jetzt etwas "spielen" und schauen ob sich das Viereck so verhält wie ich es will. Mit deiner Erklärung habe ich es jetzt in der oberen linken Ecke :thumbup:

    Das jetzt auf den Tacho zu übertragen läuft mich Sicherheit schief, darum teste ich erst mal noch etwas mit einfachen Beispielen.


    Ich hoffe man merkt das ich mir auch große Mühe gegeben habe das umzusetzen was du mir gesagt hast, sorry wenn ich ab und zu ein paar extra Runden drehen muss. :danke_ATDE:


    Schönen Abend noch!


    Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Guten Abend,


    das Quadrat war schön, aber ich hätte ja gerne ein paar andere Sachen auf meinem Display.

    Ich habe mich mal an einem viertel-Kreis in dem Quadrat versucht. Das Ergebnis sah nicht perfekt aus, liegt vielleicht an der Auflösung des Displays, aber der viertel-Kreis war erkennbar. Gemacht habe ich es so:


    Code
        memory = uarray.array('H', [TFT.BLUE for _ in range(1600)])
        for degree in range(90):
                x = int(cos(degree*pi/180)*40)
                y = int(sin(degree*pi/180)*40)
                index = (y*40)+x
                memory[index] = TFT.RED
        tft.image(0, 0, 39, 39, memory)

    Mal abgesehen davon, das die Zahlenwerte noch durch bsp. Konstanten ersetzt werden können. War das so gedacht?



    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • :bravo2:


    Juhu, vielen, vielen Dank für deine Unterstützung und Hilfe! :danke_ATDE:

    Ohne dich hätte ich es nie geschafft:)


    Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Guten Morgen,


    gestern Abend ist das mit nicht aufgefallen, aber heute morgen habe ich noch eine Fehler entdeckt, für den ich die Ursache nicht finde. Der Code ist noch der Gleiche, nur dass ich den viertel Kreis auf schwarzen Hintergrund male. Dabei habe ich in der oberen linken Ecke einen Punkt. Der müsste bei (0/0) oder (1/1) sein.



    Habe mir alle x- und y-Werte ausgeben lassen, finde aber keine Werte, die auf einen solchen Punkt hinweisen. Wenn x = 0 ist, dann ist y = 39 und wenn y = 0 ist dann ist x = 40 und dazwischen werden die Werte wie erwartet gleichmäßig erhöht bzw. verringert.


    Auf GitHub steht noch, dass man bei Darstellungsfehler 'initg' anpassen kann, das brachte aber auch keine Änderung.


    Das muss ein Problem mit dem Array sein, denn wenn ich den Kreis mit 'pixel' zeichnen lasse, passiert das nicht.




    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Versuch mal das Bild woanders malen zu lassen, ob der Punkt mit wandert oder nicht.

  • Guten Morgen,


    ja der Punkt wandert mit.

    Code
        memory = uarray.array('H', [TFT.BLACK for _ in range(1600)])
        for degree in range(90):
                x = int(cos(degree*pi/180)*40)
                y = int(sin(degree*pi/180)*40)
                print(x, y)
                index = (y*40)+x
                memory[index] = TFT.RED
        tft.image(20, 20, 59, 59, memory)


    Edit: Hier noch die Ausgaben von x /y. Vielleicht übersehe ich auch etwas.


    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Ja, du übersiehst was. Dein Quadrat ist 40 breit. Aber die Koordinate 40 existiert natürlich nicht. Die dürfen nur bis 39 gehen! So Übertritt ein Pixel den erlaubten Bereich & malt sich auf (0, 1).


    Gleiches gilt natürlich auch für y.

  • Danke für die Antwort.

    Dann kann ich entweder den Radius auf 39 setzen oder das Array vergrößern. Habe mein Quadrat auf 41x41 gesetzt und dann war der Punkt weg:thumbup:


    Wenn ich aber den Kreisausschnitt drehen will, erreiche ich das mathematisch einfach durch andere Vorzeichen. Drehe ich den Kreisausschnitt um 180° bekommt x und y ein negatives Vorzeichen:

    Code
        memory = uarray.array('H', [TFT.BLACK for _ in range(1681)])
        for degree in range(90):
                x = - int(cos(degree*pi/180)*40)
                y = - int(sin(degree*pi/180)*40)
                print(x, y)
                index = (y*40)+x
                memory[index] = TFT.RED
        tft.image(20, 20, 59, 59, memory)

    Dieser Code wirft aber wieder Punkte neben den Kreisausschnitt.

    Wie geht denn das Array mit negativen Werten um? Besser gesagt, der Index wird ja auch negativ und scheinbar weist er die meisten Pixel auch richtig zu. x- und y- Werte mit 41 gibt es nicht. Also befindet sich alles im Array, nur halt negativ.


    Es ändert an den x- und y- Werten ja auch nichts, ob ich wie oben eine '-' in die Formel einfüge oder ob ich anstatt von 0-90 von 180-270 rechne. (ist ja auch logisch)


    Mir fällt nicht ein, wie ich den Kreisausschnitt drehen kann, ohne die Vorzeichenänderung. Ich kann das Display drehen, aber das sollte ja nicht die Lösung sein. ^^


    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • An den Vorzeichen zu spielen ist das falsche Vorgehen. Das problem braucht zwei Schritte zur Lösung:


    - Verallgemeinerung des Codes: Kreisabschnitt um einen Punkt. Also Angabe von Mittelpunkt, Radius und Startwinkel.

    - Clipping. Was auch die Frage nach dem Array beantwortet: das macht da nichts, hoffentlich wirft es einen IndexError. Schlimmstenfalls überschreibt man wild Speicher. Du musst als nach dem errechnen eines Punktes auf dem Kreis prüfen, ob der im Intervall [0, Breite -1] und entsprechend der Höhe ist. Und den nur dann malen.

  • Danke für deine Antwort.


    Verallgemeinerung des Codes: Kreisabschnitt um einen Punkt. Also Angabe von Mittelpunkt, Radius und Startwinkel.

    Das wollte ich gerade umsetzen, doch ich verstehe nicht ganze wie du das meinst. Ich würde sagen mit diesem Code, kann man mit Angaben der Konstanten den Kreis in jeder Position und jeder Größe zeichnen, das sollte allgemein sein. Hast du das so gemeint?


    Für den 'image' Aufruf sind mir keine Konstantennamen eingefallen, die Sinn machen würden.


    Damit bekomme ich auch den Index-Error:

    Code
    Traceback (most recent call last):
      File "<stdin>", line 45, in <module>
      File "<stdin>", line 43, in main
      File "<stdin>", line 30, in circle
    IndexError: array index out of range


    Wenn der Code soweit in Ordnung ist, dann versuche ich mich an der Abfrage. Nur würde das keinen Sinn machen, wenn der Code schon Fehler enthält, deswegen die Zwischenfrage.


    Danke und Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?

  • Warum denn Konstanten? Warum nicht Argumente? Fuer alles, Position, Radius, Farbe. Und das "image" muss uebergeben werden als array und die Dimension eben diesen arrays. 1000 Bytes koennen ja eine Zeile mit 1000 Pixeln sein, oder 100 Zeilen mit 10 - weiss keiner, muss man also angeben.


    Es fehlt auch X_MIDDLE, was natuerlich auch einfach das x-Argument ist. Und Y_MIDDLE ist y.


    Also grob (ungetestet):


    Code
    def circe(x, y, r, arc_start, arc_end, color, data, width, height):
        for degree in range(arg_start, arg_end + 1):
            rad = degree / 180 * PI
            px = x + cos(rad) * radius
            py = y + sin(rad) * radius
            if px in range(width) and py in range(height):
                data[x + width * py] = color

    Edited once, last by MistyFlower59469 ().

  • Du musst als nach dem errechnen eines Punktes auf dem Kreis prüfen, ob der im Intervall [0, Breite -1] und entsprechend der Höhe ist. Und den nur dann malen.

    Dennis89 den Teil hast du vergessen, und da cos(180 * pi / 180) -1 ist, bekommst du ein negatives x.


    Bevor du also einen Index berechnest, und ggf. versuchst, ausserhalb des Arrays zu schreiben, brauchst du im Loop so etwas:


    Python
    if not (0 <= x <= WIDTH - 1 and 0 <= y <= HEIGHT - 1):
        continue
  • Danke für eure Antworten.


    Warum denn Konstanten? Warum nicht Argumente?

    Kann ich dir ehrlich gesagt nicht beantworten. Dass Argumente hier sinnvoller sind hat sich bei mir noch nicht so eingebrannt. Versuche aber weiterhin daran zu denken.


    Also grob (ungetestet):

    Kleinigkeiten angepasst und es funktioniert :bravo2: Damit lässt sich sogar ein Vollkreis zeichnen :)

    Code
    def circe(x, y, radius, arc_start, arc_end, color, data, width, height):
        for degree in range(arc_start, arc_end + 1):
            rad = degree / 180 * pi
            px = x - int(cos(rad) * radius)
            py = y - int(sin(rad) * radius)
            print(px, py)
            if px in range(width) and py in range(height):
                print(px, py)
                data[px + (width * py)] = color


    den Teil hast du vergessen

    Danke für den Hinweis, so weit war ich nur noch gar nicht. Wollte erst den ersten Teil abklären um bei Fehlern einfacher die Ursache zu finden.


    So jetzt müsste ich langsam mal in der Lage sein mein Display mit dem gewünschten Tacho zu füllen, ich bin gespannt.


    Vielen Dank nochmals!


    Grüße

    Dennis

    ... ob's hinterm Horizont wirklich so weit runter geht oder ob die Welt vielleicht doch gar keine Scheibe ist?