Проверьте, находится ли точка во вращающемся прямоугольнике (С#)

У меня есть программа в С# (Windows Forms), которая рисует на прямоугольнике прямоугольники. Они также могут быть нарисованы под углом (повернуты).

Я знаю каждую из начальной точки прямоугольников (верхний левый угол), их размер (ширина + высота) и их угол. Из-за поворота начальная точка не обязательно находится в верхнем левом углу, но это не имеет значения. Затем, когда я нажимаю на картинку, мне нужно проверить, в каком прямоугольнике (если есть) я нажал.

Итак, мне нужен какой-то способ проверить, находится ли точка в прямоугольнике, но мне также нужно учитывать поворот каждого прямоугольника. Кто-нибудь знает способ сделать это в С#?

Ответы

Ответ 1

Можно ли применить тот же поворот к прямоугольнику в обратную сторону?

Например, Rectangle A поворачивается на 45 градусов по часовой стрелке от его начала (верхний левый угол), тогда вы просто вращаете точку B вокруг того же начала 45 градусов COUNTER по часовой стрелке, затем проверяете, попадает ли он в прямоугольник A, вращение

Ответ 2

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

Ответ 3

Редактировать: оглянувшись назад, я использую MonoGame, а OP использует Windows Forms. Следующее для MonoGame.

Я уже давно облажался и нашел пару ответов, но на самом деле ни один из них не сработал. Вот функция С#, которая работает точно так же, как описывает OP, если не для OP, то другие люди, как и я, гуглили.

Это было головной болью, чтобы понять это. Много типичных догадок.

    bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
    {
        Matrix rotMat = Matrix.CreateRotationZ(-rotation);
        Vector2 Localpoint = P - (rect.Location).ToVector2();
        Localpoint = Vector2.Transform(Localpoint, rotMat);
        Localpoint += (rect.Location).ToVector2();

        if (rect.Contains(Localpoint)) { return true; }
        return false;
    }

И здесь это в одной строке кода. Вероятно, быстрее использовать.

    bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
    {
        if (
            rect.Contains(Vector2.Transform(P - (rect.Location).ToVector2(), Matrix.CreateRotationZ(-rotation)) + (rect.Location).ToVector2())
            ) { return true; }
        return false;
    }

Ответ 4

Я знаю, что это уже ответили, но мне пришлось сделать что-то подобное некоторое время назад. Я создал метод расширения для класса System.Windows.Point, который помог сделать то, что предложил Нейл:

    public static double GetAngle(this Point pt)
    {
        return Math.Atan2(pt.X, -pt.Y) * 180 / Math.PI;
    }

    public static Point SetAngle(this Point pt, double angle)
    {
        var rads = angle * (Math.PI / 180);
        var dist = Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y);
        pt.X = Math.Sin(rads) * dist;
        pt.Y = -(Math.Cos(rads) * dist);
        return pt;
    }

Это позволило бы мне работать с углами точек вокруг 0, 0. Поэтому, если вы знаете центр прямоугольника, который вы тестируете, вы компенсируете точку отрицательным значением этого значения (например: pt.X - = 32; pt.Y - = 32) И тогда вы примените отрицательное вращение прямоугольника (как предложено Neil: pt.SetAngle(-45);)...

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

Ответ 5

Разрешено ли перекрывать прямоугольники? Если да, хотите ли вы, чтобы все прямоугольники находились в точке или только в верхнем слое?

Ответ 6

Если вы знаете координаты углов прямоугольника, это быстрое, элегантное решение, которое включает в себя только пару точечных и скалярных продуктов: https://math.stackexchange.com/a/190373/178768

Ответ 7

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

Это может быть решено с помощью векторных произведений, но все сводится к следующему:

Итерация по углам прямоугольника:

  • проверяемая точка: P=[px,py]
  • текущий угол равен C=[cx,cy] а следующий угол равен N=[nx,ny]
  • если px*ny+cx*py+nx*cy<py*nx+cy*px+ny*cx, точка находится за пределами квадрата.