Перейти к содержимому

Уроки · 60

Угол от 0 до 360°

В уроке «Угол вектора» atan2 вернул угол от −π до π (в градусах — от −180° до 180°). Работать с таким диапазоном не всегда удобно: удобнее, когда угол всегда от 0 до 2π (в градусах — от 0° до 360°) — тогда он всегда один и тот же знак, без разбора случаев по всему коду.

Остаток от деления — это то, что осталось лишним, если разделить одно число на другое нацело. Раздели 10 на 3 — поместится три целых тройки (3 × 3 = 9), а один останется лишним: это и есть остаток, 1.

С отрицательными числами rem_euclid даёт остаток, который никогда не бывает отрицательным. Раздели -10 на 3 — поместится уже не три тройки, а четыре, только в минус (3 × -4 = -12), и тогда до -10 не хватает, а наоборот — перебор на 2. Вот этот 2 и есть остаток: 3 × -4 + 2 = -10.

С углом работает та же арифметика, просто делитель — не 3, а один полный оборот. -90, поделённое так на 360, даёт остаток 270 (360 × -1 + 270 = -90) — то есть ровно то же самое направление, но уже в привычном диапазоне. В Rust эта операция уже готова, называется .rem_euclid():

use std::f32::consts::PI;
let normalized = angle.rem_euclid(2.0 * PI);

Один вызов — и normalized всегда лежит в 0..2π, какой бы угол ни подставили: свежий результат atan2, как в уроке «Угол вектора», или угол, который растёт каждый кадр и никогда не сбрасывается, как в уроках «Вращение» и «Спутник» — и за много кадров вполне мог накрутить не один оборот. rem_euclid работает одинаково в любом из этих случаев, разбирать их по отдельности не нужно.

То же самое и в градусах, без радианов:

let normalized_degrees = angle_degrees.rem_euclid(360.0);

raw = 450° → rem_euclid: 90°

Двигай ползунок — raw изображает угол, который успел накопиться за много кадров и мог обернуться вокруг оси не один раз. Стрелка на картинке всегда стоит под результатом rem_euclid, при любом значении raw.

  • angle.rem_euclid(2.0 * PI) — остаток от деления angle на один полный оборот, 2π. Результат всегда от 0 до 2π, независимо от того, сколько оборотов было в исходном угле и в какую сторону.
  • Для отрицательных чисел rem_euclid берёт на одно деление больше в минус, лишь бы остаток не оказался отрицательным — как -90, поделённое на 360, даёт остаток 270, а не -90.
  • std::f32::consts::PI — готовая константа для числа π, чтобы не вписывать 3.14159... в код руками.
  • В демке raw — это угол, который мог накопиться за много кадров и обернуться вокруг оси не один раз. Стрелка всегда стоит под rem_euclid-результатом, при любом значении raw.