Kürzester Abstand zwischen zwei Gradmarken auf einem Kreis?

Kürzester Abstand zwischen zwei Gradmarken auf einem Kreis?
  • Schritt 1:Holen Sie sich den "rohen" Unterschied. Zum Beispiel gegeben -528.2 und 740.0 , das ist 1268.2 .

    • Einweg:raw_diff = first > second ? first - second : second - first
    • anderer Weg:raw_diff = std::fabs(first - second)
  • Schritt 2:Subtrahieren Sie ein Vielfaches von 360.0 um einen Wert zwischen 0.0 zu erhalten (einschließlich) und 360.0 (exklusiv).

    • mod_diff = std::fmod(raw_diff, 360.0)
  • Schritt 3:Wenn dieser Wert größer als 180.0 ist , subtrahieren Sie ihn von 360.0 .

    • Einweg:dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff
    • anderer Weg:dist = 180.0 - std::fabs(mod_diff - 180.0)

Es ist wahrscheinlich am lesbarsten als eine Reihe von Anweisungen:

double raw_diff = first > second ? first - second : second - first;
double mod_diff = std::fmod(raw_diff, 360.0);
double dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff;

Aber falls gewünscht, ist es nicht schwer, alles in einem einzigen Ausdruck zusammenzufassen:

180.0 - std::fabs(std::fmod(std::fabs(first - second), 360.0) - 180.0)

Sie könnten auch Vektormathematik und Trigonometrie verwenden; Winkel würden hier im Bogenmaß angegeben.

float angle(float angle1, float angle2)
{
  float x1=cos(angle1);
  float y1=sin(angle1);
  float x2=cos(angle2);
  float y2=sin(angle2);

  float dot_product = x1*x2 + y1*y2;
  return acos(dot_product);
}

Ich hatte nach einer Mikrocontroller-Lösung wie dieser gesucht, um Getriebe für eine animatronische Puppe zu suchen, und ich hatte nicht das Grunzen, um Trig richtig zu berechnen.

Die Antwort von @ruakh war eine gute Grundlage, aber ich stellte fest, dass das Schild unter bestimmten Bedingungen falsch umgedreht wurde.

Hier ist die Lösung, die für mich funktioniert hat. Diese Lösung funktioniert für Gradangaben in einem Kreis, ändert aber MAX_VALUE ermöglicht dies für einen beliebigen maximalen Bereich, der beim Messen von Zahnrad-Encoder-Impulsen nützlich ist.

Auf Arduino getestet.

#define MAX_VALUE 360

float shortestSignedDistanceBetweenCircularValues(float origin, float target){

  float signedDiff = 0.0;
  float raw_diff = origin > target ? origin - target : target - origin;
  float mod_diff = fmod(raw_diff, MAX_VALUE); //equates rollover values. E.g 0 == 360 degrees in circle

  if(mod_diff > (MAX_VALUE/2) ){
    //There is a shorter path in opposite direction
    signedDiff = (MAX_VALUE - mod_diff);
    if(target>origin) signedDiff = signedDiff * -1;
  } else {
    signedDiff = mod_diff;
    if(origin>target) signedDiff = signedDiff * -1;
  }

  return signedDiff;

}