Falsche Werte bei Sinus und Cosinus

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von tron25.

    Falsche Werte bei Sinus und Cosinus

    Hallo,

    zum Errechnen von X- und Y-Koordinaten von Punkten auf einem Kreis gibt es ja folgende Formeln:

    VB.NET-Quellcode

    1. Winkel = 180
    2. Radius = 1
    3. Winkel = 2 * PI / 360 * Winkel
    4. X = Cos(Winkel) * Radius
    5. Y = Sin(Winkel) * Radius


    Jetzt müßte nach meinem Verständnis bei einem Winkel von 0 bzw. 180 Y jeweils = 0 sein. Ist es aber nicht. Im Folgenden liste ich mal die Werte von Y in 45 Grad-Schritten auf:

    sin(2 * pi / 360 * 0) = 0
    sin(2 * pi / 360 * 45) = 0.70710678118654746
    sin(2 * pi / 360 * 90) = 1
    sin(2 * pi / 360 * 135) = 0.70710678118654757
    sin(2 * pi / 360 * 180) = 1.2246063538223773E-16
    sin(2 * pi / 360 * 225) = -0.70710678118654746
    sin(2 * pi / 360 * 270) = -1
    sin(2 * pi / 360 * 315) = -0.70710678118654768

    Ich verstehe nicht, warum bei einem Winkel von 180 Grad das Ergebnis nicht 0 ist. Bei 90 und 270 Grad ist er ja 1 bzw. -1.

    Außerdem ist der Wert bei 360 Grad, was ja gleichzusetzen mit 0 Grad ist, auch nicht 0, sondern:

    sin(2 * pi / 360 * 360) = -2.4492127076447545E-16

    Hat jemand von euch eine Idee, was da falsch läuft?
    @tron25 Das Ding heißt "Gammel-Null".
    Wenn Du tatsächlich so viele Stellen benötigst, musst Du Dir ein Epsilon festlegen, das ist eine hinreichend kleine Zahl, innerhalb der (+- dieser Wert) dann der numerische Wert auf 0 gesetzt wird.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Nein, ich benötige nur Integer.

    Es geht um Folgendes:

    Ich habe einen Text in Brailleschrift. Anhand eines eingestellten Winkels (Drehwinkel) soll der Text nun gedreht werden.

    Der ursprüngliche Text steht im "FokusArray". Um ihn drehen zu können, wird er mit Berücksichtigung des Drehwinkels in "VirtuellerFokusArray" kopiert. Danach werden die Punkte wieder zurück in "FokusArray" übertragen. Die angehängten Bilder zeigen den Originaltext und eine gedrehte Version.

    Das dritte Bild zeigt den Originaltext, dem ein Leerzeichen hinzugefügt wurde. Man erkennt, dass einige Punkte verschwunden bzw. verschoben sind. Das hat etwas damit zu tun, ob Punktwerte auf- oder abgerundet werden.

    Hat jemand eine Idee, wie dieses Problem gelöst werden kann?

    VB.NET-Quellcode

    1. MitteX1 = FokusArray.GetUpperBound(0) / 2
    2. MitteY1 = FokusArray.GetUpperBound(1) / 2
    3. MitteX2 = VirtuellerFokusArray.GetUpperBound(0) / 2
    4. MitteY2 = VirtuellerFokusArray.GetUpperBound(1) / 2
    5. 'Beim ursprünglichen Text beträgt der Drehwinkel 0 Grad.
    6. 'Als Erstes wird die Kreisbahn und der entsprechende Winkel jedes
    7. 'Braillepunktes zum Mittelpunkt ermittelt. Anhand des aktuellen
    8. 'Drehwinkels wird dann die neue Position errechnet.
    9. 'Zum Schluß wird der neue Punkt im Virtuellen Fokusarray nur dann gesetzt,
    10. 'wenn er sich im gültigen Bereich befindet.
    11. For Y = 0 To FokusArray.GetUpperBound(1)
    12. For X = 0 To FokusArray.GetUpperBound(0)
    13. 'Um den genutzten Bereich zu ermitteln, wird jeder
    14. 'nichtgesetzte Punkt mit einer 1 markiert, während jeder
    15. 'gesetzte Punkt durch eine 100 dargestellt wird.
    16. 'Bestimmen des Abstandes des Punktes zum Mittelpunkt.
    17. 'Dazu muß ein rechtwinkeliges Dreieck berechnet werden.
    18. 'Die Hypotinuse ist dabei der Abstand des Punktes zum Mittelpunkt.
    19. Breite = MitteX1 - X
    20. Hoehe = MitteY1 - Y
    21. 'Wenn Hoehe und Breite = 0 ist, bedeutet das, dass der
    22. 'aktuelle Punkt zugleich der Mittelpunkt des Fokusrechtecks
    23. 'ist. In diesem Fall sind keine weiteren Berechnungen
    24. 'notwendig. XPos und YPos können gleich auf 0 gesetzt werden.
    25. If Hoehe = 0 And Breite = 0 Then
    26. XPos = 0
    27. YPos = 0
    28. Else
    29. Abstand = Sqrt((Hoehe * Hoehe) + (Breite * Breite))
    30. Winkel = Sin(Hoehe / Abstand)
    31. Winkel = Asin(Winkel)
    32. Winkel *= 180 / PI
    33. If Winkel < 0 Then
    34. Winkel *= -1
    35. End If
    36. 'Da der Winkel nicht aussagt, in welchem Quadranten sich
    37. 'der Punkt befindet, werden die Koordinaten im
    38. 'Verhältnis zum Mittelpunkt verglichen.
    39. 'Winkel 0 beginnt rechts.
    40. If X >= MitteX1 Then
    41. If Y < MitteY1 Then
    42. Winkel = 360 - Winkel
    43. End If
    44. Else
    45. If Y < MitteY1 Then
    46. Winkel = 180 + Winkel
    47. Else
    48. Winkel = 180 - Winkel
    49. End If
    50. End If
    51. 'Jetzt wird der eingestellte Drehwinkel addiert und die neue
    52. 'Position errechnet.
    53. Winkel += Drehwinkel
    54. If Winkel > 359 Then
    55. Winkel -= 360
    56. End If
    57. Winkel = 2 * PI / 360 * Winkel
    58. XPos = Cos(Winkel) * Abstand
    59. YPos = Sin(Winkel) * Abstand
    60. End If
    61. If CInt(MitteX2 + XPos) >= 0 And CInt(MitteX2 + XPos) < VirtuellerFokus.ArrayBreite And CInt(MitteY2 + YPos) >= 0 And CInt(MitteY2 + YPos) < VirtuellerFokus.ArrayHoehe Then
    62. If FokusArray(X, Y) = 0 Then
    63. VirtuellerFokusArray(CInt(MitteX2 + XPos), CInt(MitteY2 + YPos)) = 1
    64. Else
    65. VirtuellerFokusArray(CInt(MitteX2 + XPos), CInt(MitteY2 + YPos)) = 100
    66. End If
    67. End If
    68. Next
    69. Next


    Das "FokusArray" wird nun auf die erforderliche Größe gebracht und die Punkte werden übertragen.
    Bilder
    • Screenshot 2024-09-25 133418.png

      58,72 kB, 1.920×1.080, 29 mal angesehen
    • Screenshot 2024-09-25 133534.png

      60,86 kB, 1.920×1.080, 27 mal angesehen
    • Screenshot 2024-09-25 133613.png

      57,73 kB, 1.920×1.080, 28 mal angesehen
    Der Text soll auf einem Brailledrucker ausgedruckt werden können. Zudem wird der Text auch auf einer Braillezeile bzw. einem Brailledisplay angezeigt. Diese Geräte haben Module mit 8 Braillepunkten. Da der Abstand der Stifte nicht veränderbar ist, brauche ich daher ganze Zahlen.

    tron25 schrieb:

    Nein, ich benötige nur Integer.
    Beschreib doch mal Dein Problem so, dass wir das genau so verstehen, wie Du es meinst.
    Kannst Du die Punkte mal so markieren, dass wir Herkunft und Ziel eineindeutig identifizieren können
    (die Punkte so durchnumerieren, das kommunizierende Punkte denselben Wert bekommen)?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das erste Bild zeigt ein "o" in Braille. Jedes Zeichen besteht aus 2x3 Punkten. Dabei befindet sich Punkt 1 links oben, Punkt 2 darunter und Punkt 3 links unten. Die Punkte 4 bis 6 sind auf der rechten Seite. Demnach besteht das "o" aus den Punkten 1, 3 und 5.

    Dieses Zeichen soll nun gedreht werden. Der Mittelpunkt befindet sich demnach bei X = 0,5 und Y = 1.

    Das zweite Bild zeigt das "o" um 45 Grad gedreht, das dritte um 90 Grad, usw.

    Bei den diagonalen Winkeln kann man das Punktmuster noch erahnen, allerdings gibt es bei 90 und 270 Grad einen sehr großen Bereich für Phantasie.

    FokusArray hat zwei spalten und drei Zeilen.
    FokusArray(0, 0) = 100
    FokusArray(1, 0) = 0
    FokusArray(0, 1) = 0
    FokusArray(1, 1) = 100
    FokusArray(0, 2) = 100
    FokusArray(1, 1) = 0

    Die Neuen Punkte werden in "VirtuellerFokusArray" übertragen. Dieses Array ist viel Größer, sodass es garantiert einen gedrehten Text aufnehmen kann.
    Bilder
    • Screenshot 2024-09-25 154223.png

      58,31 kB, 1.920×1.080, 25 mal angesehen
    • Screenshot 2024-09-25 155406.png

      57,2 kB, 1.920×1.080, 30 mal angesehen
    • Screenshot 2024-09-25 155420.png

      84,9 kB, 1.920×1.080, 26 mal angesehen
    • Screenshot 2024-09-25 155429.png

      86,63 kB, 1.920×1.080, 26 mal angesehen
    • Screenshot 2024-09-25 155446.png

      57,33 kB, 1.920×1.080, 23 mal angesehen
    • Screenshot 2024-09-25 155500.png

      57,66 kB, 1.920×1.080, 28 mal angesehen
    • Screenshot 2024-09-25 155508.png

      85,4 kB, 1.920×1.080, 27 mal angesehen
    • Screenshot 2024-09-25 155517.png

      87,11 kB, 1.920×1.080, 32 mal angesehen
    Hier ein VBA Beispiel:


    Visual Basic-Quellcode

    1. Sub sinus()
    2. Dim x As String, i As Long, Pi As Double
    3. Pi# = 3.14159265358979
    4. For i = 0 To 360 Step 45
    5. x = "Der Sinus von " + Format$(i, "@@@") + " Grad = " + _
    6. Format$(Sin(Pi# / 180 * i), "0.00")
    7. Debug.Print x
    8. Next i
    9. End Sub


    Ergebnis:
    Der Sinus von 0 Grad = 0,00
    Der Sinus von 45 Grad = 0,71
    Der Sinus von 90 Grad = 1,00
    Der Sinus von 135 Grad = 0,71
    Der Sinus von 180 Grad = 0,00
    Der Sinus von 225 Grad = -0,71
    Der Sinus von 270 Grad = -1,00
    Der Sinus von 315 Grad = -0,71
    Der Sinus von 360 Grad = 0,00
    Ich vermute mal die Bilder sind in der Reihenfolge 0°, 45°, 90°, 135°, usw.
    Wenn bei 0° das Bild 2x3 ist, müsste 90° dann nicht 3x2 sein? Auf dem Bild für (mutmaßlich) 90° ist es nämlich auch 2x3.
    Ist das schon Teil des Problems oder soll das so?

    Das frage ich vorwiegend, weil 0, 90, 180, 270 sind eigentlich triviale Indexvertauschungen der Punktkoordinaten; nix mit Winkeln arbeiten.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    @tron25 Ich meinte so was:

    Da es bei 6 Punkten nicht all zu viele Möglichkeiten gibt, kannst Du ein Array mit den
    Zielkoordinaten im Quellcode ablegen und dann, wenn der Punkt gesetzt ist, Dir die
    betreffenden Koordinaten aus dem Array auslesen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Natürlich könnte man beispielsweise bei 90 Grad die Koordinaten vertauschen, aber der Text sollte beliebig in 1-Grad-Schritten gedreht werden können.
    Ich habe das Beispiel von Eierlein ausprobiert. Nach seiner Rechenmethode
    Winkel = PI / 180 * Winkel

    Es ist das gleiche Resultat, wie bei mir:
    Winkel = 2 * PI / 360 * Winkel

    Wie ihr auf den folgenden Bildern sehen könnt, ist das Ergebnis das Gleiche. Es ist das Wort "hallo" in Braille zusehen.

    Beim zweiten Bild habe ich an das Ende ein Leerzeichen hinzugefügt. Dadurch verschiebt sich auch der Mittelpunkt und die Punkte werden wieder zerschossen.

    Morgen werde ich mal versuchen, ob es einen Unterschied macht, ob die Punkte um den Mittelpunkt oder um den linkesten, obersten Punkt gedreht werden. Eventuell entsteht der Fehler nur dann, wenn sich der Mittelpunkt zwischen zwei Punkten befindet.

    Ich halte euch auf dem Laufenden.
    Bilder
    • Screenshot 2024-09-25 200918.png

      57,64 kB, 1.920×1.080, 28 mal angesehen
    • Screenshot 2024-09-25 200935.png

      57,51 kB, 1.920×1.080, 31 mal angesehen
    Ich glaube nicht, dass das mit den 1-Grad Schritten funktionieren kann. Denn durch die Rasterisierung wird es Punkte geben, die neue Plätze einnehmen und solche, die noch nicht genug Verschoben wurden. Und somit werden einige Punkte auf demselben Platz landen. Nur die Fälle 90 Grad und 180 Grad sind ohne Informationsverlust möglich. Und dafür braucht man dann kein Sinus mehr.
    Da hast du Recht, aber es gibt auch Brailledrucker, die die Braillepunkte bis auf 0,05 mm genau setzen können. Bei diesen Druckern wird der Text auch deutlich besser aussehen. Mein derzeitiger Drucker kann Auflösungen von 1,6, 2 und 2,5 mm. Demnächst bekomme ich einen Neuen, der mit einer Genauigkeit von 0,1 mm drucken kann.

    Die neuen Drucker eignen sich hervorragend auch zum Erstellen von Schablonen, die beispielsweise um Knöpfe oder auf Bedienoberflächen von Microwellen oder andere Geräte geklebt werden können, damit Blinde viele Einstellungen selbständig vornehmen können.
    Ich gehe noch einen Schritt weiter zurück.
    @tron25 erstell mal eine vollständige, belastbare Problembeschreibung.
    Wenn das erste Bild in Deinem Post #13 "Hallo" heißt, was steht denn dann im zweiten Bild in Deinem Post #13?
    Sieht mir nach "eaköl" aus.
    Was haben die Inhalte beider Bilder miteinander zu tun?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Eigentlich sollte im zweiten Bild auch "hallo" stehen. Da das zweite Bild um ein Leerzeichen breiter ist, hat sich natürlich auch der Mittelpunkt verschoben. Dadurch werden einige Koordinaten durch Auf- bzw. Abrunden nicht korrekt berechnet.

    Ich habe jetzt den Drehpunkt von der Mitte nach links oben verschoben. Wie man auf den Bildern sieht, funktioniert es jetzt in beiden Fällen fast korrekt.

    Der Erste Buchstabe besteht aus den Punkten "1, 2 und 5". Der Punkt 2 wird allerdings nicht angezeigt. Den Punkt 1 habe ich abgefangen, da er gleichzeitig auch den Drehpunkt darstellt. Wenn also die Breite und Höhe des virtuellen Dreiecks zum Berechnen des Winkels gleich 0 sind, wird nur geprüft, ob der Punkt gesetzt ist.

    Alle Punkte, die in der gleichen Spalte darunter sind, werden nicht gezeichnet. Bei diesen Punkten beträgt die Breite 0 und die Höhe bzw. Hypotinuse steigt mit jeder Punktreihe um 1.

    Auch bei einem "q", welches aus den Punkten "1, 2, 3, 4, 5" besteht, fehlen die Punkte "2 und 3".

    Mir würden da zwei Lösungen einfallen, die mir aber nicht gefallen, da ich ungern mit Ausnahmen arbeite.

    1. Ich fange ebenfalls alle Punkte ab, die sich im 90 Grad Winkel vom Ausgangspunkt befinden und setze direkt den Wert für YPos.

    2. Ich setze den Drehpunkt um eine Stelle nach links und nach oben, so dass es keine Punkte gibt, die sich in der Waagerechten oder Senkrechten Linie zum Drehpunkt befinden.

    Lieber wäre mir aber eine Lösung ohne Ausnahmeregelungen.
    Bilder
    • Screenshot 2024-09-26 092020.png

      57,61 kB, 1.920×1.200, 27 mal angesehen
    • Screenshot 2024-09-26 092115.png

      57,5 kB, 1.920×1.200, 29 mal angesehen
    Ich würde ein CustomControl machen, dort dass PaintEvent nutzen. Das Braille-Alphabet hat ja nicht so viele "Chars", das Control hätte auch eine Property für den Text, wenn der geändert wurde neu malen. Musst ja nur Zeichenweise durch den String iterieren und malen, sollte ein ungültiges Zeichen eingegeben werden an dieser Position z.B. nur ein rotes Rectangle malen um zu verdeutlichen da ist was ungültig, oder aber auch die Eingaben limitieren, wenn dann z.B. ein ñ oder so eingegeben wird, einen Fehlerton abspielen und die Property für den Text nicht aktualisieren.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @tron25 Was ganz genau willst Du eigentlich erreichen?
    z.B.
    Ich möchte, dass ein Brail-Text auf einem Brail-Drucker diagonal (oder unter einem mehr oder weniger beliebigen Winkel) gedruckt wird, der so Brail-lesbar ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!