Winkeländerung berechnen



  • Hi,
    wenn man die Änderung eines Winkels (x >= 0 und x <= 360) berechnen möchte (zwei Werte), dann kommt man unvermeidbar in Kontakt mit der Definitionslücke zwischen 0 und 360. Wenn sich ein Wert direkt vor und einer direkt danach befindet, kann man nicht mehr berechnen, ob sich der Winkel vergrößert oder verkleinert hat. Weiß jemand eine Möglichkeit wie man ohne diese Problematik die Winkeländerung ohne Extremfälle berechnen kann. Ich muss dazu anmerken, dass ich schon eine Weile aus der Übung bin, was Mathe angeht.



  • Bzw. die errechnete Winkeldifferenz ist im extremfall statt 0° 360°.



  • Dazu braucht man mehr Informationen. Wenn du einfach zwei beliebige Winkel a, b, eingeschränkt auf [0,360°[ hast (selbst im Extremfall dass a=b!) kannst du nicht wissen, in welche Richtung der Winkel geändert wurde. Und wenn du eine Richtung hast, weißt du nicht, wieviele Umrundungen dazwischen passiert sind.

    Du hast wahrscheinlich gewisse "Glattheitsbedingungen" (nenn ich jetzt mal so, kA ob das der richtige Begriff ist), d.h. du nimmst an, dass deine Werte so dicht nebeneinander aufgenommen sind, dass du dazwischen keine größeren Sprünge hast. Also du postulierst beispielsweise erstmal: |a-b| < 180°, d.h. -180° < a-b < +180°. Der Fall |a-b| = 180° ist ein Sonderfall, den musst du entweder als + oder -180° ansehen.

    (Das ist eine ziemlich schwache "Glattheit", hoffentlich zappeln die Winkel nicht wirklich in diesem Bereich herum, sondern in einem wesentlich kleineren Bereich. Aber falls nichtmal die erfüllt ist, dann weißt du nichts, siehe ersten Absatz.)

    Die Alternative besteht übrigens darin, die Winkel nicht auf [0,360°[ einzuschränken.



  • Irgendwie hast du mit jedem Punkt recht. Gibt es eine Möglichkeit Winkel ohne diese Problematiken auszurechnen. Egal wie weit man den Winkelbereich erweitert, irgendwo gibts immer diese Polstellen, an denen das Programm angepasst werden muss.



  • Was ich bisher gemacht habe. Eigentlich habe ich einen Winkelbereich von 0=>180 und 0=>-180. Daraus habe ich jetzt einen Bereich von 0-360 gemacht.

    float wrap_360(float x) {
      return x < 0 ? (x + 360) : (x > 360 ? (x - 360) : x);
    }
    

    Danach berechne ich den Winkelunterschied mit:

    float delta_180(float fCurVal, float fOldVal) {
      float fCur360 = wrap_360(fCurVal);
      float fOld360 = wrap_360(fOldVal);
    
      float fVal = fCur360 - fOld360;
    
      if(fVal < -180.f) {
        fVal = (fCur360 + 360) - fOld360;
      }
      if(fVal > 180.f) {
        fVal = (fCur360 - 360) - fOld360;
      }
    
      return fVal;
    }
    

    Man sieht sehr gut, wie ich um die Polstelle zwischen 0 und 360 herumnavigiere, indem ich die Differenz auf ihre Größe überprüfe, da die Differenz normalerweise immer relativ klein sein sollte und hier 180° schon sehr viel Spielraum ist.
    Aber dieser Code ist, um ehrlich zu sein, scheiße.



  • dgrat__ schrieb:

    Was ich bisher gemacht habe. Eigentlich habe ich einen Winkelbereich von 0=>180 und 0=>-180. Daraus habe ich jetzt einen Bereich von 0-360 gemacht.

    Ich verstehe nicht, was du damit meinst.

    float delta_180(float fCurVal, float fOldVal) {
      float fCur360 = wrap_360(fCurVal);
      float fOld360 = wrap_360(fOldVal);
    
      float fVal = fCur360 - fOld360;
      
      if(fVal < -180.f) {
        fVal = (fCur360 + 360) - fOld360;
      }
      if(fVal > 180.f) {
        fVal = (fCur360 - 360) - fOld360;
      }
      
      return fVal;
    }
    

    Ich verstehe nicht, wieso du erst auf einen Bereich von 0..360 projizierst und am Ende wieder auf -180..180, das ist doch etwas umständlich, oder nicht?

    Mein Tipp von oben sähe so aus:

    float wrap_180(float x) {
      return fmodf(x + 180, 360) - 180;
    }
    
    float delta_180(float fCurVal, float fOldVal) {
      return wrap_180(fCurVal - fOldVal);
    }
    


  • dgrat__ schrieb:

    Hi,
    wenn man die Änderung eines Winkels (x >= 0 und x <= 360) berechnen möchte (zwei Werte), dann kommt man unvermeidbar in Kontakt mit der Definitionslücke zwischen 0 und 360. Wenn sich ein Wert direkt vor und einer direkt danach befindet, kann man nicht mehr berechnen, ob sich der Winkel vergrößert oder verkleinert hat.

    Welche Definitionslücke?
    Welcher Winkel?

    Ich finde, du hast Dein Problem nicht gut beschrieben.

    Wenn du zwei Punkte auf einem Kreis hast und Dich fragst, ob du den einen im Uhrzeigersinn oder gegen den Uhrzeigersinn auf dem Kreis wandern lassen musst, bis du den anderen Punkt erreichst, dann sollte dir doch klar sein, dass immer beides möglich ist. Fragst Du dich, in welcher Richtung der Weg kürzer ist? Wenn ja, dann willst du die Winkeldifferenz auf [-180,180) beschränken. Addiere oder subtrahiere einfach solange 360, bis du in diesem Bereich bist. Mit fmod ginge das auch, ist aber anscheinend nicht so einfach, das korrekt zu machen. fmod(a,b) kann auch negativ sein. Bashar hätte das so schreiben müssen:

    float wrap_180(float x)
    {
      x = std::fmod(x    ,360);     // x jetzt in (-360,360)
      x = x + 360;                  // x jetzt in (0,720)
      x = std::fmod(x+180,360)-180; // Beschränkung auf [-180,180)
      return x;
    }
    

    Wenn du zwei Werte, die jeweils im Bereich [0,360) liegen, subtrahierst, bist du ja schon innerhalb (-360,360), kannst dir also das erste fmod in dem Fall sparen.

    Edit:
    Oh, ich sehe gerade, C++11 hat noch eine praktischere Funktion für diesen Fall zu bieten:

    float wrap_180(float x)
    {
      return std::remainder(x,360);
    }
    

    🙂

    Die Benennung der Funktionen fmod und remainder ist allerdings irreführend. fmod berechnet den Divisionsrest wobei der Quotient zur 0 gerundet wird, remainder den Divisionsrest, wobei der Quotient zur nächsten Ganzzahl gerundet wird. Diese Version von wrap_180 bilder aber -180 auf -180 und +180 auf +180 ab ... rein theoretisch, so wie sie definiert wurde.



  • Winkel gehen von -\infty bis \infty und eine Winkeldifferenz von ±2π\pm 2\pi entspricht einer vollen Umdrehung. Wer dir was anderes erzählen will lügt.

    Hast du deine Berechnung fertig, kannst du gerne wieder einschränken (wenn du dabei keine wichtigen Informationenverlierst), ansonsten vollkommen unnötig.



  • krümelkacker schrieb:

    Mit fmod ginge das auch, ist aber anscheinend nicht so einfach, das korrekt zu machen. fmod(a,b) kann auch negativ sein. Bashar hätte das so schreiben müssen:

    Oh, ich hatte die Doku nur überflogen und angenommen, dass fmod irgendwie sinnvoll (= so wie ichs brauche :D) definiert sei.


Log in to reply