Winkelberechnung fehlerhaft wegen Rundungsfehler
-
Hallo zusammen,
Ich versuche seit ein paar Tagen ein Programm zu schreiben das eine beliebige Figur auf dem Bildschirm rotieren lassen kann. (Ohne DirectX oder OpenGL).
Funktionsweise für einen Punkt:
Ich habe einen Ausgangspunkt x = 200 und y = 180.
Durch drücken der Links-Taste wird der Radius und der Winkel zur Mitte des Bildschirms ermittelt. Anschließend 1 auf den Winkel addiert und die X und Y Punkte neu berechnet und gezeichnet. Der alte Punkt wird gelöscht damit es auch eine Animation ist.Ansich funktioniert es auch aber....
da der Bildschirm aus rechteckigen Pixeln besteht habe ich bei jeder Neuberechnung einen klitzekleinen Versatz. Somit läuft es leider nicht ganz rund und die Figur sieht nach ein paar Umdrehungen aus wie Salat.Ich lasse mir den Radius im Fenstertitel anzeigen und er schwankt immer +- 2 Pixel vom Soll.
Hat jemand einen Tipp für mich wie ich immer den Richtigen Radius erhalten kann?
DirectX kann es ja auch berechnen, also muss es ja irgendwie gehen oder?Ich programmiere nicht in C++. Daher bitte keinen Code schreiben, nur ein paar Worte zur Vorgehensweise.
Wie gesagt es kann nur daran liegen.Danke und Gruß, Nicky
-
Schau dir mal an was eine Rotationsmatrix tut. Die Rotation so implementieren wie du es grad machst ist jedenfalls keine gute Idee. Und speicher deine Punkte eben nicht in int- sondern in float-Koordinaten. Anstatt inkrementell zu rotieren könntest du auch einfach die Ausgangskoordinaten speichern und dann die neuen Koordinaten immer mit dem absoluten Winkel daraus berechnen.
-
das sollte an sich so nicht passieren, kannst du mal den relevanten teil vom code posten, vielleicht hast du einen bug.
-
Hallo,
Welchen Vorteil hat es die Bildschirmpunkte auch als Float zu speichern? Die Pixeldaten haben doch nur ganze Zahlen?
Im großen und ganzen beziehen sich die Berechnungen auf dem rechtwinkligen Dreieck. Erst die Differenz auf der X-Achse errechnen (gk) und dann auf der Y-Achse (ak). Beides zum Quadrat, Addieren und die Wurzel ziehen. Somit hab ich den Radius meines Kreises (oder Hypothenuse). Damit kann ich den Winkel zum Mittelpunkt berechnen. Ich nutze überall Floatwerte. Bei der Rückgabe in Bildschirmkoordinaten runde ich diese auf Int-Werte (gibt ja keine 80,64 Pixel)
Hier mal der Code dafür:
fclex ;FPU Fehlerflag löschen
finit ;FPU Initialisierenfild gk
fild gk
fmul
fstp quad1fild ak
fild ak
fmul
fstp quad2fld quad1
fld quad2
fadd
fsqrt
fstp p1.hl ;Das ist der Radiusfild gk
fld p1.hl
fdiv
fstp sin ;Der Sinus des Winkelsfild ak
fld p1.hl
fdiv
fstp cos ;Der Cosinus des Winkelsfld sin
fld cos
fpatan
fstp bomfld pi2
fld bom
fdiv
fld kreis
fxch
fdiv
fstp winkel ;hier der errechnete Winkelfld winkel
fld winkelerhoehung ;Winkel + 1
fadd
fstp winkel ;neuen Winkel als Float speichern
fwaitfclex
finitfld kreis
fld winkel
fdiv
fstp quad1 ;360 / Winkelfld pi2 ; 6,283185 / (360/Winkel)
fld quad1
fdiv
fstp bom ;Wert zwischenspeichern;Sin
fld bom ;vom zwischengespeicherten Wert den Sin berechnen
fsin
fld p1.hl
fmul
fild mpy
fxch
fsub
fist p1.y ;Sinus = Y-Koordinate (Integer);Cos
fld bom ;vom zwischengespeicherten Wert den Cos berechnen
fcos
fld p1.hl
fmul
fild mpx
fadd
fist p1.x ;Cosinus = X-Koordinate (Integer)
fwaitIch hoffe jemand kann das lesen.
Ich habe auch in dem Programm den Radius zwischengespeichert und weiter genutzt, damit läuft alles nach Plan. Sobald ich diesen Wert aber einmal lösche habe ich einen kleinen Versatz zum "Vorkreis".Hoffe jemand kann helfen
Nicky
-
Supernicky schrieb:
Welchen Vorteil hat es die Bildschirmpunkte auch als Float zu speichern? Die Pixeldaten haben doch nur ganze Zahlen?
Na das hast du doch selber schon gesagt. Auch wenn deine Ausgangspunkte ganzzahlige Koordinaten haben, wenn du deinen Punkt um x Grad rotierst dann hat er nichtmehr notwendigerweise ganzzahlige Koordinaten. Die Wahrscheinlichkeit ist sogar verschwindend gering. Also wird gerundet. Und dabei ein Fehler gemacht. Wenn du dann ausgehend von diesen fehlerbehafteten Koordinaten weiterrotierst kanns gut sein dass das Ganze irgendwohin abhaut. Darum entweder mit float oder Fixkomma arbeiten oder z.B. einfach nicht inkrementell rotieren.
-
Hallo dot,
was ist "nicht inkrementell rotieren" gemeint??
-
supernicky schrieb:
was ist "nicht inkrementell rotieren" gemeint??
Ich würde es so deuten, daß du nicht die aktuelle Position jeweils um 1 Grad drehst, sondern dir den Rotationswinkel vom Ausgangspunkt aus merkst und jeweils die Originalpunkte um n Grad drehst.
-
exakt
-
Genau. Das ist dein Problem. Du solltest weder in float noch in sonstwas speichen, du sollst einfach _gar nicht_ speichern und nur anzeigen. Was du anzeigst, ergibt sich dann stets aus (200;180)*Rotationsmatrix.
-
Hallo zusammen,
ich weiß was ihr meint. Das funktioniert auch, solange ich nur um eine Achse drehe.
Sobald ich das Object auch um die Z-Achse drehen lasse, verändere ich automatisch die X- und Y Koordinaten auf unvorhersehbare Maße (man weiß ja nicht wie weit der User das Object nach hinten dreht)...Daher bin ich förmlich gezwungen den Winkel und den Radius aus dem IST-Zustand neu zu berechnen.
Ich mach noch ein paar Versuche...
Nicky