L'argomento del laboratorio di giovedi' 11/5/06 sembra sia risultato particolarmente difficile. Pubblico quindi queste istruzioni aggiuntive:
Definite una vostra sottoclasse di Panel (AWT) o JPanel (Swing)
che disegni, per esempio, un cerchio.
Questa classe dovra' ridefinire la funzione paint (AWT) o
paintComponent (Swing) per disegnare il cerchio.
Per adesso disegnate direttamente in device coordinates, vale a dire
riferendovi ai pixel. Per esempio, supponendo che il pannello sia
300x300 pixel disegnate un cerchio inscritto nel rettangolo di diagonale
(50,50)-(250,250).
E' anche opportuno che il costruttore di questa classe prenda
come argomenti le dimensioni larghezza, altezza che intendiamo
dare al pannello (nel nostro esempio sono 300,300).
Un pannello infatti avrebbe per default dimensioni preferite nulle.
Questo si ottiene in Swing chiamando dentro al costruttore la
funzione setPreferredSize.
In AWT invece occorre memorizzare larghezza, altezza in due attributi
e definire a parte la funzione getPreferredSize in modo che ritorni
una dimensione costruita in base a larghezza, altezza date
(new Dimension(larghezza, altezza)).
Create poi un Frame o JFrame e metteteci dentro un'istanza di questa sotto-classe di pannello definita da noi. Notare che facendo pack sul frame vengono utilizzate le dimensioni preferite del pannello, che abbiamo impostato noi.
Aggiungete alla vostra classe un attributo di classe Voronoi per
contenere il diagramma di Voronoi da disegnare.
Aggiungete un oggetto di classe Voronoi fra gli argomenti del costruttore
della classe, tale oggetto ricevuto in argomento sara' memorizzato
nell'attributo.
Il frame principale, che contiene il pannello, dovra' crearlo passandogli un
diagramma di Voronoi gia' esistente.
Dunque esso crea un diagramma di Voronoi (usando il costruttore della classe
Voronoi), poi costruisce un pannello per disegnarlo passandogli tale
diagramma di Voronoi, e infine lo aggiunge a se stesso, esegue pack e si
rende visibile.
A regime il frame principale sara' poi la finestra principale della vostra
interfaccia, e presumibilmente creera' molti altri oggetti passandogli in
argomento il diagramma di Voronoi.
E' importante quindi che il diagramma di Voronoi sia uno (creato nel frame
principale) e passato a tutti.
Nella funzione paint (AWT) o paintComponent (Swing), tutti i punti da disegnare (i siti di Voronoi) si ottengono dal diagramma di Voronoi tramite la funzione getPoints, che ritorna un array di oggetti di classe PointXY. Scorrete dunque tale array e disegnate ogni punto con un simbolo (es. cerchio, quadrato...).
MA ATTENZIONE: non potete usare per il disegno le coordinate vere del punto. I punti infatti sono espressi in user space, mentre il disegno avviene in device space. Occorre una traduzione di coordinate. Per questo, vedere il punto successivo.
Come prima, ma aggiungete il disegno delle regioni.
Per ogni sito, la regione corrispondente si ottiene dal diagramma di
Voronoi tramite la funzione getRegion.
La funzione ritorna un array di PointXY, che sono i vertici del poligono
di contorno della regione.
Anche questi non si possono disegnare direttamente, ma bisogna tradurre le coordinate (vedere il punto successivo). Inoltre PRIMA DI DISEGNARE e PRIMA DI TRADURRE LE COORDINATE bisogna fare il clipping della regione, cioe' ritagliare la sola parte di regione che sta dentro al rettangolo di riferimento del diagramma di Voronoi. Per questo usate la funzione clipRegion della classe Clipping, che prende la regione di Vornoi vera e la ritaglia, restituendone in vertici in un altro array.
Il vostro diagramma di Voronoi ha un certo rettangolo di riferimento,
che puo' avere dimensioni arbitrarie e trovarsi in posizione arbitraria
rispetto all'origine. In generale indichiamo la sua
diagonale con (minX,minY)-(maxX,maxY).
Il vostro pannello in cui dovete disegnare ha una certa dimensione
in pixel (per esempio 300x300), inoltre ha l'origine fissata
in alto a sinistra.
L'idea qui e' che che tutto e solo il rettangolo di riferimento di Voronoi deve essere disegnato nel pannello occupandolo tutto (in realta' si potrebbe prendere un pochino di piu' del rettangolo di riferimento del diagramma di Voronoi).
Le coordinate del diagramma di Voronoi (user coordinates) devono essere tradotte in coordinate del pannello (device coordinates), per poter disegnare il diagramma dentro al pannello.
NON e' possibile semplificarsi il lavoro disegnando direttamente in coordinate di device, cioe' supponendo che il rettangolo di riferimento del diagramma di Voronoi coincida sempre con il rettangolo del pannello in cui disegnamo.
Occorre invece una traduzione. Ci sono due modi possibili:
Fare la traduzione "a mano" definendo due funzioni di conversione,
una per le x e una per le y, di questa forma (per le x - analogo
per le y):
int convertCoordinateX
(float user_x,float min_x,float max_x,int panel_width)
che in base
alla coordinata in user space, ai limiti minimi e massimi sulle x
del rettangolo di riferimento del diagramma di Voronoi,
e alla larghezza del pannello, calcola
la coordinata in device space.
Questo calcolo consiste in una traslazione e in una scalatura.
Prima la traslazione per portare la coordinata min_x di Voronoi in zero.
Poi una scalatura per portare la larghezza max_x-min_x a coincidere
con la larghezza del pannello.
Prima di scrivere il codice studiate bene, su carta, come deve essere
la formula di calcolo.
Le dimensioni correnti del pannello si trovano con la funzione getSize.
Far fare la traduzione a Java aggiungendo nello stato del
sistema grafico una trasformazione affine.
Questa trasformazione affine dovra' fare quanto scritto sopra, cioe'
una traslazione e una scalatura.
Prima la traslazione per portare la coordinata min_x di Voronoi in zero.
Poi una scalatura per portare la larghezza max_x-min_x a coincidere
con la larghezza del pannello.
Attenzione: nel codice vanno scritte in ordine inverso!
Riferimento: vedere
dispense.