Come si affrontano i wrapper angolari quando li si confronta?

1

L'angolo A è un angolo di laurea che continua ad aumentare di incrementi e l'Angolo B è il punto di arresto di Angolo A (si pensi 'Spin-the-bottle' dove Angolo A è l'angolo corrente della bottiglia. L'Angolo B è l'angolo necessario per indicare la tua cotta e la bottiglia gira ad una velocità fissa in senso orario).

Per fare questo, ho cercato di confrontare Angolo A e Angolo B con disuguaglianze. Se l'angolo A è di 60 gradi e l'angolo B è di 80 gradi, questo non è un problema. Se l'angolo A è 350 gradi e l'angolo B è 10 gradi, tuttavia, la disuguaglianza pensa che l'angolo A abbia attraversato l'angolo B anche se non lo è stato.

Come faccio a confrontare gli angoli quando avvolgono a 360 gradi?

Questo è uno pseudo-codice per quello che ho finora:

int AngleB = 30;
int AngleA = 300;

void Update() {
    AngleA += 13;
    if (AngleA > AngleB) {
        AngleA = AngleB;
    }
}

Aggiornamento: ecco il mio nuovo metodo che avvolge l'Angolo A rispetto all'angolo B:

double GetAngleDifference(double from, double to)
{
    double difference = to - from;
    while (difference < -180) double += 360;
    while (difference > 180) double-= 360;
    return difference;
}
    
posta JPtheK9 06.01.2015 - 00:11
fonte

4 risposte

1

Qualsiasi angolo è equivalente all'angolo + 360 gradi.

Quindi se aumenti a , ma a > b (numericamente), quindi aggiungi 360 a b all'inizio. Ora a < b funziona per il tuo ciclo.

per es.

a = 270
b = 45
b += 360 // = 405
while (a < b)
  a += ... // 270 up to 405

Se stai riducendo a ma b > a (numericamente), quindi aggiungi 360 a a all'inizio. Ora a > b funziona per il tuo ciclo.

per es.

a = 10
b = 310
a += 360 // = 370
while (a > b)
  a -= ...  // 370 down to 310

Questo non è lo pseudocodice completo, ma illustra i due casi in cui devi preoccuparti di "incrociare" il segno 360.

    
risposta data 06.01.2015 - 04:59
fonte
1

Se la domanda è Come faccio a sapere se A ha attraversato B? potresti usare la seguente logica:

    a := A mod 360.
    b := B mod 360.
    prev := a > b.
    A := A + 13.
    a := A mod 360.
    current := a > b.
    Return: current not = prev

Lo pseudo-codice sopra ritorna con TRUE se, e solo se, A ha incrociato B. Ciò significa che devi aggiornare la posizione di A e, allo stesso tempo, scoprire se la croce è appena avvenuta.

    
risposta data 06.01.2015 - 02:00
fonte
0

Non capisco completamente il problema che si pone, ma sospetto che sarebbe utile trovare l'angolo più piccolo tra AngleA e AngleB, dove l'angolo più piccolo è nell'intervallo da -180 a 180. Questo può essere fatto con l'aritmetica del modulo.

La maggior parte dei linguaggi di programmazione ha una qualche forma di una funzione modulo, ma il loro comportamento varia, vedi pagina wikipedia . Per trovare l'angolo più piccolo, in realtà si desidera utilizzare una funzione modulo che arrotonda il numero intero più vicino. Si scopre che questo non è molto comune. Tuttavia, è piuttosto semplice da implementare (come descritto al link ):

double ModNearestInt(double a, double b) {
    return a - b * round(a / b);
}

Ha la proprietà nice che il resto restituito è

  • sempre nell'intervallo [-b / 2, + b / 2]
  • sempre la distanza più breve da zero

Quindi, per trovare l'angolo più piccolo tra AngleA e AngleB, puoi fare:

double smallestAngle = ModNearestInt(AngleA - AngleB, 360.0);

Per rilevare A incrociando B in direzione positiva se è noto che AngleA sta aumentando, è sufficiente verificare che l'angolo più piccolo cambi segno da negativo a positivo. Quando il segno di smallestAngle cambia da positivo a negativo e AngleA è in aumento, questo corrisponde a A crossing (B + 180). Allo stesso modo, se è noto che AngleA sta diminuendo, allora A incrocia B quando il segno di smallestAngle cambia da positivo a negativo.

    
risposta data 06.01.2015 - 04:41
fonte
0

How do deal with angle wraparounds when comparing them?

Dato, AngleA, AngleB c'è più di una differenza . Sotto le differenze ci sono 270 e -90 a seconda se ci muoviamo in senso orario o antiorario.

int AngleA = 30;
int AngleB = 300;

Possibili convenzioni:

1) Angolo con la magnitudine minore: -90.

2) Più piccolo dei 2 magnitudini: 90.

3) In una rotazione fissa: ad es. in senso orario 270.

4) Entrambi: -90, 270.

Continuiamo con # 3 o 270 gradi dato il codice double from, double to dell'OP.

How do I compare angles when they wraparound at 360 degrees?

La prima considerazione è qual è il dominio di from,to ?
Potrebbero avere valore o sono limitati a [-360 ... 360] o [0 ... 360) o cosa?
Supponiamo che [-360 ... 360].

Successivamente, considera type:
Per int , usa % , l'operatore resto .
Per double , usa fmod , la funzione resto .
Il resto differisce dal mod.

Quando l'obiettivo è che la risposta risieda in [0 ... 360) ....

Con numeri interi, questo è semplice.

int GetAngleDifferenceClockwise_int(int from, int to)  {
  int diff = (from - to)%360;  // diff now in (-360 ... 360) range
  if (diff < 0) diff += 360;   // diff now in [   0 ... 360) range
  return diff;
}

Con double , questo più interessante. Per preservare la precisione, in genere l'intervallo di destinazione è [-180 ... 180) anziché [0 ... 360).

double GetAngleDifferenceClockwise_double(double from, double to)  {
  double diff = fmod(from - to, 360.0); // diff now in (-360.0 ... 360.0) range
  if (diff >= 180.0) diff -= 360.0;     // diff now in (-360.0 ... 180.0) range
  else if (diff < -180.0) diff += 360.0;// diff now in [-180.0 ... 180.0) range
  return diff;
}
    
risposta data 18.11.2018 - 14:38
fonte

Leggi altre domande sui tag