L'obiettivo e' disegnare in Java il diagramma di Voronoi di un insieme di punti (ved. documentazione del progetto).
In pratica dovete definire un vostro componente Java personalizzato che "si disegna" disegnando su se stesso il diagramma di Voronoi. Tale componente sara' poi inserito all'interno della gerarchia di contenimento della vostra interfaccia, e quindi visualizzato.
La vostra interfaccia, per ora, potra' essere semplicemente
una finestra principale (Frame) che contiene come unico sotto-componente
questo pannello.
Il diagramma di Voronoi da visualizzare potra' essere fisso e costruito da
programma (come nel Main di esempio dato nel
progetto).
Ci sono vari punti chiave da risolvere:
Non occorre consegnare nulla, questo e' solo un esercizio che vi sara' utile per il progetto finale del corso.
SUGGERIMENTO:
E' molto utile programmare tenendo aperta
a fianco una finestra sul sito con il manuale on-line delle
classi Java:
http://java.sun.com/j2se/1.4.2/docs/api/index.html
In genere non e' necessario che l'area destinata a contenere il disegno del diagramma di Voronoi abbia un comportamento particolare. Quindi possiamo definire la nostra nuova classe semplicemente come sottoclasse di Panel (in AWT) o JPanel (in Swing).
Nel seguito chiamo NOSTRA_CLASSE questa nostra sotto-classe di pannello.
Un pannello in Java non contiene nulla, fino a che non aggiungiamo
componenti al suo interno.
L'uso che facciamo ora del pannello e' anomalo nel senso che non lo
usiamo per contenere altri componenti ma per disegnare sul suo
sfondo. Quindi lo usiamo vuoto.
Siccome Java assegna dimensione preferita nulla a un pannello vuoto,
e' opportuno ridefinire, nella nostra sotto-classe NOSTRA_CLASSE,
la dimensione preferita.
Questa si ridefinisce in Swing chiamando la funzione setPreferredSize
(ved. manuale on-line), e in AWT reimplementando la funzione
getPreferredSize (ved. manuale on-line) in quanto AWT non
fornisce la funzione setPreferredSize.
La nostra classe NOSTRA_CLASSE deve poter accedere al diagramma di Voronoi, che sara' un oggetto di classe Voronoi.
IMPORTANTE:
Quando il nostro componente viene usato nell'interfaccia complessiva
del progetto, tipicamente abbiamo gia'
un oggetto diagramma-di-Voronoi, che compare come variabile in qualche
altra classe della vostra interfaccia, in genere nella
classe che realizza la finestra principale.
La nostra classe (come abbiamo appena detto)
avra' anch'essa come variabile un oggetto di classe
Voronoi.
Tale variabile dovra' contenere lo stesso oggetto contenuto nella variabile
di classe Voronoi che sta all'interno della finestra principale.
Il costruttore della nostra classe NOSTRA_CLASSE
prendera' in argomento un oggetto di
classe Voronoi e lo assegnera' alla sua variabile interna.
Tale costruttore e' chiamato dal costruttore
della classe che corrisponde alla finestra principale dell'interfaccia
passando come argomento la variabile di classe Voronoi che sta all'interno
della finestra principale.
In questo modo la finestra principale e il pannello condividono lo stesso
diagramma di Voronoi.
In pratica, nella classe principale:
Voronoi global_voronoi; NOSTRA_CLASSE voronoi_panel;Nella classe NOSTRA_CLASSE da noi definita per disegnare il diagramma di Voronoi:
Voronoi local_voronoi;Il costruttore della classe NOSTRA_CLASSE:
NOSTRA_CLASSE(Voronoi vor,...) { local_voronoi = vor; ... }Nel costruttore dela classe principale:
global_voronoi = new Voronoi(...); ... voronoi_panel = new NOSTRA_CLASSE(global_voronoi...);
Il nostro diagramma di Voronoi ha siti con coordinate
reali comprese in un generico rettangolo
di diagonale (x1,y1)-(x2,y2): questo rettangolo e' il nostro
user space.
Il pannello in cui disegnamo ha coordinate intere comprese nel
rettangolo (0,0)-(W,H) dove W e H sono larghezza e altezza del pannello
in pixel: questo rettangolo e' il nostro
device space.
Per poter disegnare, dobbiamo tradurre le coordinate da user space
a device space, ovvero portare il rettangolo (x1,y1)-(x2,y2)
a coincidere con il rettangolo (0,0)-(W,H) mediante operazioni
di traslazione e scalatura.
Questo puo' essere fatto in due modi:
Scandire l'array dei siti del diagramma (restituito dalla funzione getPoints della classe Voronoi).
Per ogni sito farsi ritornare i vertici di contorno nella regione di Voronoi (funzione getRegion).
La regione puo' essere illimitata o comunque puo' estendersi
molto al di fuori della parte di piano inquadrata nel nostro pannello
di disegno. Questo puo' causare problemi a Java.
Percio' e' preferibile fare il "clipping" della regione rispetto
all'estensione del pannello di disegno (cioe' calcolare l'intersezione e
tenere solo la parte dentro), prima di disegnare.
Questo si fa con la funzione clipRegion della classe Clipping.
NOTA: il clipping avviene prima della traduzione da user a device
space, quindi il rettangolo da usare
per il clipping e' quello di user space.
Ora la regione puo' essere disegnata riempiendo l'interno
(funzione fillPolygon della classe Graphics)
o tracciando il contorno (drawPolygon).
Se si decide di fare entrambe le cose, prima riempire tutti gli
interni e poi tracciare tutti i contorni
(occorrono due cicli sui vertici).
In generale ricordare che le cose vengono disegnate nell'ordine in cui
sono eseguiti i comandi di disegno, e quello che viene disegnato
dopo copre quello che era stato disegnato prima.
Per esempio, se disegnamo anche i siti (bisogna disegnare un ellisse
centrato nel punto con la funzione fillArc di Graphics),
bisogna disegnarli dopo aver disegnato le regioni piene, altrimenti
vengono coperti.