Как рассчитать угол поворота прямоугольника, учитывая его 4 точки - PullRequest
1 голос
/ 03 июля 2019

У меня есть набор 2D точек.Я сделал оценку собственных векторов его ковариации.Сделал трансформацию на новую основу и нашел там ограничивающую рамкуДля простоты приведу код в октаве ниже.Точки задаются как: переменная точек с формой Nx2

mycov = cov(points);
[V, E] = eig(mycov);
new_basis_points = V*points';

Затем в коде я оцениваю максимальные и минимальные значения для каждой оси и устанавливаю четыре точки:

points = [[minX, minY], 
          [minX, maxY],
          [maxX, minY],
          [maxX, maxY]];

Теперь япреобразование обратно в старую базу:

old_basis_bounding_box = V'*points';

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

Проблема в том, что порядок точек в old_basis_bounding_box не определен.Поэтому я не уверен, какие две точки выбрать для оценки угла.

Как мне поступить?

1 Ответ

2 голосов
/ 05 июля 2019

Illustration

Я считаю, что угол alpha (отмечен зеленым на изображении) - это то, что вы ищете.Предполагая, что самая низкая точка прямоугольника равна O(0, 0), этот угол можно легко рассчитать как cos -1 (a / sqrt (a ^ 2 + b ^ 2)), где B(a,b) - точкас наименьшим положительным уклоном .Что касается D ≠ O (где D - точка с наименьшей координатой оси Y), просто переместите все это на вектор OD так, чтобы D = O.

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

Мой псевдокод:

    struct Point
    {
        double x, y, angle;
        Point (double x, double y): x(x), y(y) {}
    };

    bool SortByY (Point a, Point b)
    {
        return a.y < b.y;
    }

    bool SortByAngle (Point a, Point b)
    {
        return a.angle < b.angle;
    }

    double GetRotationAngle(vector<Point> points)
    {
        sort (points.begin(), points.end(), SortByY);

        // If there are 2 points lie on the same y-axis coordinates, simply return 0
        if  (points[0].y == points[1].y) return 0;

        Point D = points[0];

        for (int i=1; i<4; i++)
        {
            // Move the whole thing by vector OD
            double a = points[i].x -= D.x;
            double b = points[i].y -= D.y;

            // Keep in mind that in C++, the acos function returns value in radians, you may need to convert to degrees for your purposes.
            points[i].angle = acos(a / sqrt(a*a+b*b));
        }

        sort (points.begin()+1, points.end(), SortByAngle);
        return points[1].angle;
    }
...