Ecco uno di quei problemi che tanto fanno dannare i programmatori e che invece tanto piacciono ai matematici. Il monitor, come tutti voi sanno, funziona secondo una logica a piano cartesiano dove l’asse delle X va da sinistra a destra, mentre l’asse delle Y va dall’alto verso il basso. Questo è molto comodo dal punto di vista del posizionamento delle finestre e degli oggetti nello schermo, ma risulta alquanto scomodo quando si tratta di voler rendere a video un grafico standard, ovvero con l’asse delle Y rivolto verso l’alto. Per fortuna il framework ci viene incontro per risolvere questo problema, con un pò di geometria…
Innanzitutto vediamo come si comporta con un sistema normale di coordinate lo schermo del pc, e quindi di una form di un nostro ipotetico programma, disegnando 3 punti presi a caso:

Decidiamo di voler disegnare lo stesso grafico ma avendo l’asse delle Y rivolto verso l’alto, come fare? Innanzitutto abbiamo bisogno di qualche concetto di geometria di base. Supponiamo di avere un punto nel piano cartesiano, alle coordinate (2, 1). Se applichiamo al punto una rotazione di 90°, ritroviamo il punto alle coordinate (-1, 2). Vediamolo sotto forma di grafico:

Ho volutamente inserito sotto al grafico anche il calcolo matriciale che ho utilizzato per ottenere le nuove coordinate del punto. Se volessimo ruotare il grafico di 180° o di 270°, basterebbe che usassimo rispettivamente le matrici
e
Questi valori non sono messi a caso, basta infatti dare un’occhiata ad un libro di geometria, per scoprire che il modo per ruotare un sistema di riferimento cartesiano per far sì che coincida con un altro, è basato su una matrice di rotazione, per l’esattezza questa:
GDI+ ci mette a disposizione oltre alla rotazione anche un sistema di traslazione, in modo tale che la matrice finale risulti una matrice 3×3 (3 righe e 3 colonne), questa per l’esattezza:

dove per l’appunto abbiamo nella parte alta la matrice suddetta di rotazione degli assi, in basso un vettore di traslazione (per i 2 assi) e a destra un vettore di 3 elementi che sono fissi e predefiniti dalla libreria. Applicando perciò un qualsiasi tipo di trasformazione a questa matrice, vediamo riflessi i cambiamenti direttamente sulla nostra form. E’ da dire che i valori in alto identificano la rotazione non sono fissi, quindi è possibile manipolare questi valori a nostro piacimento. Ad esempio, per invertire il senso di un solo asse di riferimento (in questo caso l’asse Y), basta prendere una matrice identità e cambiare di segno il secondo coefficiente, così:
che a livello logico di libreria diventa questa:

o molto meglio via codice, all’interno dell’evento OnPaint della form, questo:
Matrix mat1 = new Matrix(1, 0, 0, -1, 0, 0); e.Graphics.Transform = mat1;
che genera in output nient’altro che questo:

che diventa utilissimo nel caso volessimo graficare dei dati utilizzando le classiche impostazioni del piano cartesiano. Per capire meglio, vi spiego in dettaglio quali dati della matrice occorre utilizzare per generare la matrice di trasformazione… nel caso io abbia come nel caso appena presentato l’intenzione di invertire la posizione dei punti rispetto all’asse Y, allora devo avere questa matrice.
Essendo che l’ultima colonna è fissata, alla creazione della nuova matrice il framework ci mostra soltanto 6 dati, che altro non sono che i 6 coefficienti delle prime 2 colonne della matrice. Occorre perciò inserire i dati nell’ordine:
- matrice di rotazione (per colonne)
- vettore di traslazione
e quindi esattamente: 1, 0, 0, -1, 0, 0. Il rosso è la prima colonna della matrice, il verde la seconda. Il blu è il vettore in basso.
Questo è il codice utilizzato per generare tutto il grafico sopra:
//creo la matrice di trasformazione
Matrix mat1 = new Matrix(1, 0, 0, -1, 0, Height - 50);
//e la applico al graphics della form
e.Graphics.Transform = mat1;
//applico una ulteriore traslazione per lasciare spazio agli assi di riferimento
e.Graphics.TranslateTransform(10,10, MatrixOrder.Append);
//creo la penna per disegnare gli assi come frecce
Pen axPen = new Pen(Brushes.Black);
axPen.Width = 1;
axPen.EndCap = LineCap.ArrowAnchor; //per visualizzare il termine delle linee come frecce
//disegno gli assi
e.Graphics.DrawLine(axPen, 0, 0, 0, Height - 50);
e.Graphics.DrawLine(axPen, 0, 0, Width - 50, 0);
//disegno la gradazione dei 2 assi
for (int i = 0; i < Width - 60; i += 10)
{
e.Graphics.DrawLine(new Pen(Brushes.Black), i, 0, i, -5);
e.Graphics.DrawLine(new Pen(Brushes.Black), 0, i, -5, i);
}
//creo una lista di 3 punti
List<point> points = new List();
points.Add(new Point(65,60));
points.Add(new Point(153,247));
points.Add(new Point(253, 105));
//e disegno ognuno di questi
for (int i = 0; i < 3; i++)
{
int X = points[i].X;
int Y = points[i].Y;
e.Graphics.DrawEllipse(new Pen(Brushes.Blue, 2), X - 1, Y - 1, 2, 2);
}
Ovviamente il codice non è ottimizzato, è solo un esempio di come funziona il meccanismo, sperando che possa essere d’aiuto a qualcuno ![]()
Buona geometria ![]()
di Denis, postato alle 00:01









Ho necessità di leggere i valori dei colori impostati per ogni pixel in una immagine nel formato jpeg.
SALUTI