2009-08-06 14 views
14

Ho un programma in C# (Windows Form) che disegna alcuni rettangoli su una picturebox. Possono essere disegnati anche ad angolo (ruotati).Verificare se un punto è in un rettangolo ruotato (C#)

Conosco ciascun punto iniziale dei rettangoli (angolo superiore sinistro), la loro dimensione (larghezza + altezza) e la loro angolazione. A causa della rotazione, il punto iniziale non è necessariamente l'angolo in alto a sinistra, ma non importa qui. Poi, quando clicco sulla casella immagine, ho bisogno di controllare in quale rettangolo (se presente) ho cliccato.

Quindi ho bisogno di un modo per verificare se un punto è in un rettangolo, ma ho anche bisogno di prendere in considerazione la rotazione di ogni rettangolo. Qualcuno sa di un modo per farlo in C#?

+0

I rettangoli ruotano attorno all'origine, all'angolo superiore sinistro o a un altro punto arbitrario? – outis

risposta

18

È possibile applicare la stessa rotazione applicata al rettangolo al punto in ordine inverso?

Ad esempio, il rettangolo A viene ruotato di 45 gradi in senso orario dall'origine (angolo in alto a sinistra), quindi si ruota il punto B attorno alla stessa origine di 45 gradi in senso orario, quindi si verifica se rientra nel rettangolo A -rotation

+0

Questa è certamente la strada da percorrere, ma non riesco a ottenere la mia matematica in questo momento. Grazie. – Ove

+0

Penso che la soluzione ideale dipenda dal framework che hai impostato nella tua applicazione. In alcuni casi, penso che l'idea di Outis di un buffer z sia più ideale. Tieni presente che la sua soluzione è la stessa con cui gli oggetti di rendering di GPU sono in 3D. –

+1

Per essere onesti, hai portato la "z-" all'idea di buffering. – outis

5

È possibile mantenere una seconda immagine non visualizzata in cui si disegnano i duplicati dei rettangoli, ciascuno colorato in modo univoco. Quando l'utente fa clic sulla casella immagine, trova il colore del pixel corrispondente nella seconda immagine, che identificherà il rettangolo selezionato.

+1

Sarebbe uno spreco di memoria e sarebbe lento. – Ove

+1

La soluzione Outis funziona.Lo sto utilizzando nel progetto CF in questo momento per eseguire test di successo particolarmente complessi. Ma controlla anche: http://msdn.microsoft.com/en-us/library/system.drawing.rectangle.contains(VS.80).aspx La classe Rectangle ha un metodo Contains che può essere utilizzato per il punto di test contenimento. –

+0

+1 per la soluzione non matematica – JeffH

1

I rettangoli potrebbero sovrapporsi? Se sì, vuoi che tutti i rettangoli in un punto, o solo quello nel livello superiore?

2

So che questa era già risposta ma ho dovuto fare qualcosa di simile qualche tempo fa. Ho creato un metodo di estensione per la classe System.Windows.Point che ha contribuito a fare esattamente quello che Neil ha suggerito:

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

Questo mi avrebbe permesso di lavorare con gli angoli di punti circa 0, 0. Quindi, se si conosce il centro del rect che si sta testando si compenserebbe il punto con il negativo di questo valore (ad esempio: pt.X - = 32; pt.Y - = 32) E quindi si applicherà la rotazione negativa del rettangolo (come suggerito di Neil: pt.SetAngle (-45);) ...

Ora se il punto si trova entro 64, 64 si sa di aver premuto il rettangolo. Più precisamente stavo controllando un pixel di un'immagine ruotata per assicurarmi di colpire un pixel di un colore specifico.

0

ho pasticciano questo per un po 'di tempo e Ho trovato un paio di risposte, ma nessuna di queste ha funzionato. Ecco una funzione C# che fa esattamente come OP descrive, se non per OP poi altre persone che googlano come me.

E 'stato un mal di testa per capirlo. Molte delle supposizioni tipiche.

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

E qui è in una singola riga di codice. Probabilmente più veloce da usare.

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