2009-08-06 48 views
14

que tiene un programa en C# (Windows Forms), que atrae a unos rectángulos en un cuadro de imagen. También se pueden dibujar en un ángulo (girado).Comprobar si un punto está en un rectángulo girado (C#)

sé cada uno de los rectángulos punto de partida (esquina superior izquierda), su tamaño (ancho + alto) y su ángulo. Debido a la rotación, el punto de inicio no es necesariamente la esquina superior izquierda, pero eso no importa aquí. Luego, cuando hago clic en la casilla de imágenes, necesito verificar en qué rectángulo (si hay) he hecho clic.

así que necesito alguna manera de comprobar si un punto está en un rectángulo, pero también tienen que tener en cuenta la rotación de cada rectángulo. ¿Alguien sabe de una manera de hacer esto en C#?

+0

¿Están los rectángulos girados sobre el origen, la esquina superior izquierda u otro punto arbitrario? – outis

Respuesta

18

¿Es posible aplicar la misma rotación aplicada al rectángulo hacia el punto invertido?

Por ejemplo, el rectángulo A se gira 45 grados en el sentido de las agujas del reloj desde su origen (esquina superior izquierda), luego gira el punto B alrededor del mismo origen 45 grados hacia la derecha, luego verifica si cae dentro del rectángulo A pre -rotación

+0

Este es ciertamente el camino a seguir, pero parece que no puedo sacar mis cálculos en este momento. Gracias. – Ove

+0

Creo que la solución ideal depende del marco que haya configurado en su aplicación. En algunos casos, creo que la idea de Outis de un z-buffer es más ideal. Tenga en cuenta que su solución es la misma que el renderizado de GPU en 3D. –

+1

Para ser justos, trajiste la "z-" a la idea de almacenamiento en búfer. – outis

5

Se podría mantener una segunda imagen, no visualizado donde se dibuja duplicados de los rectángulos, de color de forma única. Cuando el usuario hace clic en el cuadro de imagen, busque el color del píxel correspondiente en la segunda imagen, que identificará en qué rectángulo se hizo clic.

+1

Eso sería un desperdicio de memoria y sería lento. – Ove

+1

La solución de Outis funciona.Lo estoy usando en el proyecto de CF en este momento para hacer algunas pruebas de impacto particularmente complejas. Pero también mira: http://msdn.microsoft.com/en-us/library/system.drawing.rectangle.contains(VS.80).aspx La clase Rectangle tiene un método Contiene que se puede usar para probar el punto contención. –

+0

+1 para solución no matemática – JeffH

1

¿Los rectángulos podrían superponerse? En caso afirmativo, ¿le gustaría tener todos los rectángulos en un punto, o solo uno en la capa superior?

2

Sé que esto ya fue contestada pero tenía que hacer algo similar hace un tiempo. He creado un método de extensión para la clase System.Windows.Point que ayudó a hacer exactamente lo que sugiere Neil:

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

Esto me permitirá trabajar con los ángulos de puntos alrededor de 0, 0. Así que si sabes el centro del rect que está probando, compensaría el punto con el valor negativo de este valor (por ejemplo: pt.X - = 32; pt.Y - = 32) Y luego aplicaría la rotación negativa del rectángulo (como se sugiere) por Neil: pt.SetAngle (-45);) ...

Ahora bien, si el punto está dentro de 64, 64 ustedes saben que se pulsa el rectángulo. Más específicamente, estaba comprobando un píxel de una imagen girada para asegurarme de que golpeé un píxel de un color específico.

0

He estado jugando esto por un tiempo y ahora he encontrado algunas respuestas, pero ninguna de ellas realmente funcionó. Aquí hay una función de C# que hace exactamente lo que OP describe, si no fuera por OP y otras personas en Google como yo.

Fue un dolor de cabeza resolver esto. Muchas de las conjeturas típicas.

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

Y aquí está en una sola línea de código. Probablemente más rápido de usar.

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