4 votes

Angle de serrage sur une plage arbitraire

J'ai besoin d'une fonction pour réduire un angle (en degrés) dans une plage arbitraire. [min,max] . Voici quelques exemples : Angle range examples

Les zones colorées représentent la plage d'angle valide.

  • Dans l'image n° 1, ang doit être fixé à max (-90)

  • Dans l'image n°2, ang doit être fixé à min (135)

  • Dans l'image n° 3, ang doit être fixé à min (135)

Voici ce que j'ai pour l'instant :

static float clamp_angle(float ang,float min,float max)
{
    ang = normalize_angle(ang); // normalize_angle transforms angle into [-180,180) range
    min = normalize_angle(min);
    max = normalize_angle(max);
    if(angle_in_range(ang,min,max) == false)
    {
        if(abs(get_angle_difference(ang,min)) < abs(get_angle_difference(ang,max))
            ang = min; // Clamp to min if we're closer to min than max
        else
            ang = max;
    }
    return ang;
}

Ce qui me manque, c'est la fonction angle_in_range ( true si l'angle est compris dans l'intervalle, sinon false ).
Quel serait le moyen le plus simple de déterminer si l'angle est compris ou non dans l'intervalle ?

2voto

Serikov Points 592

Vous pouvez normaliser les angles de manière à ce que ang devienne 0 et que les valeurs min et max correspondent à [-180 ; 180]. Vous pouvez ensuite vérifier si l'angle est compris dans l'intervalle fourni, comme ceci :

float clamp_angle(const float ang, const float min, const float max)
{
    float n_min = normalize180(min-ang);
    float n_max = normalize180(max-ang);

    if (n_min <= 0 && n_max >= 0)
    {
        return ang;
    }
    if (abs(n_min) < abs(n_max))
        return min;
    return max;
}

<a href="http://coliru.stacked-crooked.com/a/b071757e67aecbd0" rel="nofollow noreferrer">Live On Coliru</a>

0voto

Dmitry Lachinov Points 91

Supposons que vous utilisiez l'ordre des aiguilles d'une montre. La distance entre min et max dans l'ordre des aiguilles d'une montre est dist(min, max) = (max - min)mod N Supposons que le point se trouve à l'intérieur de la région. Alors dist(min,A) + dist(A,max) = dist(min,max). Vous pouvez maintenant mesurer la distance entre le point A, min et max : dist(min, A)= (A - min)modN dist(A, max)=(max-A)modN. Si A se trouve à l'extérieur de la région, la somme des distances doit être égale à N+dist(min, max), si A se trouve à l'intérieur, elle doit être égale à dist(min,max).

Dans votre cas, N = 360, toutes les valeurs sont comprises dans [0,360].

Edit : Dans la plupart des langues, le comportement de (-x)modX n'est pas défini, vous devez donc convertir manuellement -x en nombre positif, par exemple (-x + X)modX où x se trouve dans [0,X).

0voto

Facundo Points 1

Si vous souhaitez limiter l'angle de manière à ce qu'il reste dans la plage mais qu'il s'enroule autour lorsqu'il atteint le maximum ou le minimum (au lieu de se limiter aux limites), vous pouvez utiliser cette fonction assez simple que j'ai créée en utilisant Python :

def clamp_to_range(value, min, max):
     return (value % (max - min)) + min

Il se comporte de la manière suivante :

>>> for i in range(0, 30): print("|{:<30}|{:<30}|".format(" "*(clamp_to_range(i, 4, 15)) + "♥", " "*i + "♥"))
...
|    ♥                         |♥                             |
|     ♥                        | ♥                            |
|      ♥                       |  ♥                           |
|       ♥                      |   ♥                          |
|        ♥                     |    ♥                         |
|         ♥                    |     ♥                        |
|          ♥                   |      ♥                       |
|           ♥                  |       ♥                      |
|            ♥                 |        ♥                     |
|             ♥                |         ♥                    |
|              ♥               |          ♥                   |
|    ♥                         |           ♥                  |
|     ♥                        |            ♥                 |
|      ♥                       |             ♥                |
|       ♥                      |              ♥               |
|        ♥                     |               ♥              |
|         ♥                    |                ♥             |
|          ♥                   |                 ♥            |
|           ♥                  |                  ♥           |
|            ♥                 |                   ♥          |
|             ♥                |                    ♥         |
|              ♥               |                     ♥        |
|    ♥                         |                      ♥       |
|     ♥                        |                       ♥      |
|      ♥                       |                        ♥     |
|       ♥                      |                         ♥    |
|        ♥                     |                          ♥   |
|         ♥                    |                           ♥  |
|          ♥                   |                            ♥ |
|           ♥                  |                             ♥|

comme je l'ai mentionné, il s'enroule autour. Si vous souhaitez plutôt réduire la valeur aux limites spécifiées, vous pouvez utiliser cette fonction :

def clip_to_range(value, min_, max_):  # underscores added to avoid name collisions
     return min(max_, max(value, min_))

Dans ce cas, c'est ce qui se passera :

>>> for i in range(0, 30): print("|{:<30}|{:<30}|".format(" "*clip_to_range(i, 4, 15) + "♥", " "*i + "♥"))
...
|    ♥                         |♥                             |
|    ♥                         | ♥                            |
|    ♥                         |  ♥                           |
|    ♥                         |   ♥                          |
|    ♥                         |    ♥                         |
|     ♥                        |     ♥                        |
|      ♥                       |      ♥                       |
|       ♥                      |       ♥                      |
|        ♥                     |        ♥                     |
|         ♥                    |         ♥                    |
|          ♥                   |          ♥                   |
|           ♥                  |           ♥                  |
|            ♥                 |            ♥                 |
|             ♥                |             ♥                |
|              ♥               |              ♥               |
|               ♥              |               ♥              |
|               ♥              |                ♥             |
|               ♥              |                 ♥            |
|               ♥              |                  ♥           |
|               ♥              |                   ♥          |
|               ♥              |                    ♥         |
|               ♥              |                     ♥        |
|               ♥              |                      ♥       |
|               ♥              |                       ♥      |
|               ♥              |                        ♥     |
|               ♥              |                         ♥    |
|               ♥              |                          ♥   |
|               ♥              |                           ♥  |
|               ♥              |                            ♥ |
|               ♥              |                             ♥|

Un analogue de la C à la clamp_to_range ressemblerait à ceci :

#include <math.h>

float clampInRange(float value, float min, float max)
{
    return fmod(value, max - min) + min;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X