← Все вопросы

Как повернуть вектор на заданный угол и как сделать поворот на 90° без тригонометрии?

Задан 17 месяцев назад247 просмотров2 ответа
7

Нужно повернуть точку/вектор вокруг начала координат. Для произвольного угла понятно, что нужны синус и косинус, а вот поворот ровно на 90° хочется делать в целых числах, без потери точности. Как это записать?

2 ответа

11
✓ Принятый ответ — помог автору

Поворот вектора (x, y) на угол θ против часовой стрелки задаётся матрицей поворота:

x' = x·cos θ − y·sin θ
y' = x·sin θ + y·cos θ
// поворот на угол ang (радианы), CCW. double, неизбежно
pair<double,double> rotate(double x, double y, double ang) {
    double c = cos(ang), s = sin(ang);
    return { x * c - y * s, x * s + y * c };
}

Но для углов, кратных 90°, синус и косинус — это ±1 и 0, поэтому поворот делается точно в целых числах:

P rot90(const P& v)  { return { -v.y,  v.x }; } // +90° CCW
P rot270(const P& v) { return {  v.y, -v.x }; } // -90° (или +270°) CCW
P rot180(const P& v) { return { -v.x, -v.y }; } // 180°

Поворот на 90° CCW переводит (x, y) в (−y, x) — это прямо следует из матрицы при θ=90°. Используй его, когда нужна перпендикуляр-нормаль к отрезку или поворот в задачах на сетке: остаёшься в long long, без double. Все операции O(1).

5

Полезный приём: нормаль (перпендикуляр) к вектору — это его поворот на 90°. Если у тебя ребро AB и нужна внешняя/внутренняя нормаль, бери rot90(B - A) — получишь перпендикулярный вектор той же длины, в целых числах. Дальше знак (внутрь/наружу) определяешь через cross с любой внутренней точкой.

И предупреждение про произвольный угол: cos/sin дают double, и многократные повороты накапливают ошибку. Если нужно повернуть много раз на один угол, посчитай c и s один раз и применяй матрицу, а не вызывай cos в цикле — и быстрее, и стабильнее. Для целочисленных задач старайся свести всё к поворотам на 90°.

Ваш ответ

Войдите, чтобы ответить на вопрос.