2009-08-06 1 views
14

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

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

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

+0

Являются ли прямоугольники поворотными относительно начала координат, верхнего левого угла или другой произвольной точки? – outis

ответ

18

Можно ли применить тот же поворот, примененный к прямоугольнику, к точке в обратном направлении?

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

+0

Это, безусловно, путь, но я не могу понять свою математику в этот момент. Спасибо. – Ove

+0

Я думаю, что идеальное решение зависит от структуры, которую вы создали в своем приложении. В некоторых случаях я думаю, что идея Outis о z-буфере более идеальна. Имейте в виду, что его решение аналогично действиям GPU для рендеринга в 3D. –

+1

Чтобы быть справедливым, вы принесли «z-» в буферную идею. – outis

5

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

+1

Это было бы пустой тратой памяти, и это было бы медленным. – Ove

+1

Решение Outis работает.Я использую его в проекте CF прямо сейчас, чтобы сделать особенно сложное тестирование. Но также проверьте: http://msdn.microsoft.com/en-us/library/system.drawing.rectangle.contains(VS.80).aspx Класс Rectangle имеет метод Contains, который может использоваться для тестирования точки сдерживание. –

+0

+1 для не-математического решения – JeffH

1

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

2

Я знаю, что на это уже был дан ответ, но я должен был сделать что-то подобное некоторое время назад. Я создал метод расширения для класса 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). Затем вы применяете отрицательное вращение прямоугольника (как предложено by Neil: pt.SetAngle (-45);) ...

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

1

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

0

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

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

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; 
    }