Подтвердить что ты не робот

Нормализовать ориентацию между 0 и 360

Я работаю над простой процедурой поворота, которая нормализует вращение объектов между 0 и 360 градусами. Мой код на С#, кажется, работает, но я не совсем этому доволен. Может ли кто-нибудь улучшить код ниже, сделав его немного более надежным?

public void Rotate(int degrees)
    {
        this.orientation += degrees;

        if (this.orientation < 0)
        {
            while (this.orientation < 0)
            {
                this.orientation += 360;
            }
        }
        else if (this.orientation >= 360)
        {
            while (this.orientation >= 360)
            {
                this.orientation -= 360;
            }
        }
    }
4b9b3361

Ответ 1

Использовать арифметику по модулю:

this.orientation += degrees;

this.orientation = this.orientation % 360;

if (this.orientation < 0)
{
    this.orientation += 360;
}

Ответ 2

Это нормализуется к любому диапазону. Полезно для нормализации между [-180, 180], [0,180] или [0,360].

(это в С++ хотя)

//Normalizes any number to an arbitrary range 
//by assuming the range wraps around when going below min or above max 
double normalise( const double value, const double start, const double end ) 
{
  const double width       = end - start   ;   // 
  const double offsetValue = value - start ;   // value relative to 0

  return ( offsetValue - ( floor( offsetValue / width ) * width ) ) + start ;
  // + start to reset back to start of original range
}

Для ints

//Normalizes any number to an arbitrary range 
//by assuming the range wraps around when going below min or above max 
int normalise( const int value, const int start, const int end ) 
{
  const int width       = end - start   ;   // 
  const int offsetValue = value - start ;   // value relative to 0

  return ( offsetValue - ( ( offsetValue / width ) * width ) ) + start ;
  // + start to reset back to start of original range
}

Так что в принципе то же самое, но без пола. Версия, которую я лично использую, является общей, которая работает для всех числовых типов, а также использует переопределенный пол, который ничего не делает в случае интегральных типов.

Ответ 3

Это можно упростить до следующего.

public void Rotate (int degrees) {
    this.orientation = (this.orientation + degrees) % 360;
    if (this.orientation < 0) this.orientation += 360;
}

С# следует тем же правилам, что и C и С++, а i % 360 предоставит вам значение между -359 и 359 для любого целого числа, тогда вторая строка должна обеспечить его в диапазоне от 0 до 359 включительно.

Если вы хотите быть сдержанным, вы можете получить его до одной строки:

    this.orientation = (this.orientation + (degrees % 360) + 360) % 360;

что бы сохранить его положительным при любых условиях, но это неприятный взлом для сохранения одной строки кода, поэтому я бы этого не сделал, но я объясню это.

Из degrees % 360 вы получите число между -359 и 359. Добавление 360 изменит диапазон на 1 и 719. Если orientation уже положительный, добавление этого будет гарантировать, что оно все еще есть, а окончательный % 360 вернет его в диапазон от 0 до 359.

Как минимум, вы можете упростить код, так как можно комбинировать if и while. Например, результат условий в этих двух строках:

if (this.orientation < 0)
while (this.orientation < 0)

всегда одно и то же, поэтому вам не нужны окружающие if.

Итак, с этой целью вы можете сделать:

public void Rotate (int degrees) {
    this.orientation += degrees;
    while (this.orientation <   0) this.orientation += 360;
    while (this.orientation > 359) this.orientation -= 360;
}

но я по-прежнему буду использовать версию модуля, так как он избегает циклов. Это будет важно, когда пользователь запустит 360 000 000 000 для вращения (и они сделают это, поверьте мне), а затем найдите, что они должны взять ранний обед, пока ваш код не мелькает: -)

Ответ 4

Я как бы быстро высмеял это в AS3, но должен работать (вам может понадобиться += по углу)

private Number clampAngle(Number angle)
{
    return (angle % 360) + (angle < 0 ? 360 : 0);
}

Ответ 5

формула для переориентации круговых значений, чтобы удерживать угол между 0 и 359:

angle + Math.ceil( -angle / 360 ) * 360

обобщенная формула для ориентации угла сдвига может быть:

angle + Math.ceil( (-angle+shift) / 360 ) * 360

в котором значение сдвига представляет собой циклический сдвиг, например, я хочу, чтобы значения от -179 до 180 затем были представлены как:   угол + Math.ceil((-angle-179)/360) * 360

Ответ 6

Я предпочитаю избегать циклов, условных выражений, произвольных смещений (3600) и вызовов Math.____():

var degrees = -123;
degrees = (degrees % 360 + 360) % 360;
// degrees: 237

Ответ 7

Добавьте любое кратное на 360 градусов, между которыми могут быть ваши возможные входные значения (чтобы взять их выше нуля), и просто возьмите оставшиеся с%, как это

angle = 382;
normalized_angle = (angle+3600) %360;
//result = 22

Приведенный выше пример может принимать углы ввода до -3600. Вы можете добавить любое число (кратное 360), безумно высокое, что сделало бы входное значение положительным первым.

Обычно во время анимации ваше предыдущее значение frame/step, вероятно, уже было бы нормализовано предыдущим шагом, поэтому вам будет полезно просто добавить 360:

normalized_angle = (angle+360) %360;