RISPOSTE AD ALCUNE QUESTIONI EMERSE IN LABORATORIO

12/5/06

L'argomento del laboratorio di giovedi' 11/5/06 sembra sia risultato particolarmente difficile. Pubblico quindi queste istruzioni aggiuntive:

  1. Proposta di percorso per costruire quanto richiesto procedendo a tappe
  2. Delucidazioni sulla traduzione delle coordinate da user space (in cui e' definito il diagramma di Voronoi) a device space (coordinate in pixel della finestra).

Proposta di percorso per costruire quanto richiesto procedendo a tappe

1. Costruiamo un componente che disegna "qualcosa"

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.

2. Disegnare i siti del diagramma di Voronoi

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.

3. Disegnare anche le regioni del diagramma di Voronoi

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.

Delucidazioni sulla traduzione delle coordinate da user space a device space

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:

  1. 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.

  2. 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.