【问题标题】:Clamp angle to arbitrary range夹角到任意范围
【发布时间】:2017-02-15 10:34:04
【问题描述】:

我需要一个函数来将角度(以度为单位)限制在任意范围[min,max]。这里有些例子:

彩色区域代表有效角度范围。

  • 在图像 #1 中,ang 应该被限制在 max (-90)
  • 在图像 #2 中,ang 应被限制为 min (135)
  • 在图像 #3 中,ang 应该被限制在 min (135)

这是我目前所拥有的:

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;
}

我缺少的是函数angle_in_range(如果角度在范围内则为true,否则为false)。
确定角度是否在范围内的最简单方法是什么?

【问题讨论】:

标签: c++ range angle


【解决方案1】:

您可以标准化角度,使 ang 变为 0,min 和 max 映射到 [-180; 180)。然后您可以检查角度是否在提供的范围内,如下所示:

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;
}

Live On Coliru

【讨论】:

    【解决方案2】:

    假设您使用顺时针顺序。 cw 顺序中 min 和 max 之间的距离是 dist(min, max) = (max - min)mod N 假设点在区域内。然后 dist(min,A) + dist(A,max) = dist(min,max)。现在您可以测量点 A、min 和 max 之间的距离:dist(min, A)= (A - min)modN dist(A, max)=(max-A)modN。如果是A外部区域,那么距离之和应该是N+dist(min,max),如果在里面应该是dist(min,max)

    在您的情况下,N = 360,所有值都位于 [0,360)

    编辑:在大多数语言中 (-x)modX 的行为是未定义的,因此您应该手动将 -x 转换为正数,例如(-x + X)modX 其中 x 位于 [0,X)

    【讨论】:

      【解决方案3】:

      如果你想限制角度以使其保持在范围内,但在达到最大值或最小值时会环绕(而不是限制到极限),那么你可以使用我使用 python 编写的这个相当简单的函数:

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

      它的行为是这样的:

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

      正如我提到的,它环绕。如果您想将值裁剪到指定的限制,可以使用此函数:

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

      在这种情况下会发生这种情况:

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

      clamp_to_range 函数的 C 模拟如下所示:

      #include <math.h>
      
      float clampInRange(float value, float min, float max)
      {
          return fmod(value, max - min) + min;
      }
      

      【讨论】:

      • 你不应该在模运算之前从值中减去“min”吗?即返回 (value - min_val) % (max_val - min_val)) + min_val。另一个注意事项:你不应该使用 min 或 max 作为变量名,因为 min 和 max 是内置的 python 函数
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多