I sistemi di riferimento sono molto utilizzati in grafica, ma hanno una base geometrica molto antica e in Fisica sono stati l'entità più utilizzata di questo secolo. I sistemi a cui si sta facendo "riferimento" sono quelli Cartesiani.
Un sistema di riferimento è immaginato e disegnato come una coppia o una tripla di assi (dipende se si lavora su un piano o nello spazio) perpendicolari tra loro e che si intersecano in un punto. Tale punto, detto "origine" è scelto ad hoc da colui che se ne serve. La scelta dell'origine e la particolare rotazione di un certo sistema di riferimento è arbitraria perchè in conclusione si deve ottenere un risultato che deve essere valido per qualsiasi tipo di sistema di riferimento. Se ciò non accade significa che quello che si vuole dimostrare non è corretto.
Quando la Terra "era piatta" oltre agli infiniti sistemi di riferimento possibili, veniva considerato il "Sistema di Riferimento Universale" quello che aveva come origine il centro del disco della Terra. Poi Keplero e Galilei con l'introduzione del Sistema Eliocentrico hanno "spostato" l'origine del Sistema di Riferimento Universale al centro del Sole. E' chiaro che tutto ciò che era dimostrato come funzionante nel Sistema Universale doveva essere tale anche in un sistema di riferimento qualsiasi anche se in moto rispetto a quello Universale, a patto che tale moto fosse rettilineo ed unifirme. Cioè un Sistema di Riferimento Inerziale.
Le Teorie relativistiche di Albert Einstein resero obsoleto anche il Sistema Eliocentrico. Infatti Einstein contiunò ad affermare l'equivalenza dei sistemi di riferimento (Principio di Equivalenza), ma introdusse nelle trasformazioni delle coordinate tra sistemi diversi un'altra coordinata: il tempo. Ciò rese spiegabili alcuni fenomeni incomprensibili con la Fisica precedente. In realtà tali trasformazioni erano già note ai tempi di Einstein perchè ricavate in precedenza da Lorentz per scopi diversi (Trasformazioni di Lorentz).
Ma qui non vogliamo fare un trattato di Fisica, però la descrizione precedente è stata utile ad introdurre i sistemi di riferimento utilizzati in computer grafica.
Come prima notizia c'è da dire che anche se "fisicamente" obsoleto, in computer grafica il Sistema di riferimento Universale esiste. Questo perchè l'Universo reale, almeno quello che a noi appare, è unico per tutti (qui ci sarebbe da discutere per secoli!), mentre le finestre delle applet dei vari utenti che usano svariati computers sono molte. Allora per far sì che non si creino equivoci quando si posizionano oggetti grafici sul piano delle applet, i programmatori che hanno realizzato le funzioni grafiche di Java hanno stabilito che per default esiste un sistema di riferimento universale che ha come origine il punto in alto a sinistra del rettangolo dell'applet e si sviluppa con l'asse X avente verso positivo a destra e con l'asse Y avente verso positivo in basso.
Allora si può dire che la computer grafica usuale, sia 2D che 3D, tratta il piano o lo spazio dello schermo grafico come un Sistema Eliocentrico, cioè dotato di un sistema di riferimento universale. Univesale perchè è l'unico che è sicuramente comune a tutti gli utenti della computer grafica.
Tutte le classi che abbiamo presentato fino ad ora fanno esclusivamente riferimento al sistema di riferimento universale di default. Ora qui ci preoccuperemo di poter far riferimento ad altri sistemi scelti a nostro piacimento.
A cosa può servire, mentre si sviluppa un software grafico, poter far uso di un sistema di riferimento diverso da quello universale? Semplice! Immaginate di aver la posizione di alcuni oggetti rispetto al sistema di riferimento universale, ma vi si chiede di doverli posizionare rispetto ad un sistema di riferimento particolare, con origine ad una certa posizione e assi ruotati di un certo angolo. E' chiaro che basterebbe applicare methods del tipo sposta() e ruota(), ma dopo un pò la cosa comincia ad essere complicata. Se poi vi si chiede di usare addiruttura un sistema di riferimento mobile...
Realizzazione di un esempio con tre sistemi di riferimento
All'inizio può sembrare complesso modificare tutte le class presentate affinchè facciano uso anche di sistemi di riferimento qualsiasi. Pensandoci un pò si capisce che tutto ciò che resta da fare è la sola azione di modificare, come al solito, la class Punto(). Tutte le classi geometriche rappresentati entita hanno ora un method inSistema(Sistema s) che modifica le variabili del punto in corso adattandole al nuovo sistema di riferimento Il punto in corso modificato da tale method rappresenta il punto richiesto in coordinate utente convertito in coordinate universali perchè i methods disegna() delle varie classi lavorano su coordinate universali.
Il method inSistema() prevede un parametro di tipo Sistema, che è la classe che indica appunto il sistema di riferimento per il quale bisogna convertire le coordinate del punto (espresso in coordinate utente) in coordinate universali.
Punto inSistema(Sistema
sis) {
void inSistema(Sistema sis) {
x=x*sis.fscalaX;
y=y*sis.fscalaY;
sposta(new Punto(0, 0), sis.origine);
ruota(sis.origine, sis.rotazione);
}
Inoltre bisogna creare una class Sistema():
class
Sistema extends entita {
Punto
origine=new Punto();
double
rotazione;
double
fscalaX, fscalaY;
// sistema
di riferimento universale
Sistema() {
origine= new Punto();
rotazione=0;
fscalaX=1;
fscalaY=1;
}
Questo constructor permette di creare un sistema di riferimento avente un origine in un particolare punto e una certa rotazione rispetto ad un altro sistema o a quello universale. Inoltre è possibile passare i parametri fscaleX e fscaleY affinchè il sistema di riferimento abbia unità di misura diverse da altri sistemi se si imposta per questi parametri valori diversi da 1 ma uguali. Se, invece, si impostano valori diversi per fscaleX e fscaleY allora si ottiene un sistema di riferimento non isometrico, cioè dove le unità di misura sull'asse X e Y non hanno la stessa lunghezza se misurata da un osservatore esterno al sistema (gli osservatori interno al sistema non se ne accorgerebbero perchè facente parte di esso, comunque ne parleremo nel prossimo articolo).
//
Sistema di riferimento con origine e rotazione e scala
Sistema(Punto orgine, double rotazione, double fscalaX, double fscalaY)
{
this.origine=orgine;
this.rotazione=rotazione;
this.fscalaX=fscalaX;
this.fscalaY=fscalaY;
}
Quest'altro constructor, invece, permette di stabilire il verso positivo dell'asse X semplicemente con la posizione di un punto. In questo modo viene calcolata automaticamente la rotazione del sistema.
//
Sistema di riferimento con origine, punto per verso positivo X e scala
Sistema(Punto orgine, Punto suX, double fscalaX, double fscalaY) {
this.origine=orgine;
rotazione=(new Linea(origine, suX)).angoloXY();
this.fscalaX=fscalaX;
this.fscalaY=fscalaY;
}
Questo method ritorna un gruppo di entita che rappresentano l'icona del sistema di riferimento in corso. Se passato al method disegna() allora viene resa visibile l'icona sulla finestra dell'applet.
//
ritorna un gruppo di entita' che rappresentano l'icona del sistema
gruppo icona() {
gruppo SRicona = new gruppo();
Punto orig=new Punto (0, 0);
Linea asseX = new Linea(orig.clonato(), orig.clonato().relativo(30, 0));
Linea asseY = new Linea(orig.clonato(), orig.clonato().relativo(0, 30));
Poligono frecciaX = new Poligono(asseX.P2.clonato(), 5, 3);
Poligono frecciaY = new Poligono(asseY.P2.clonato(), 5, 3);
frecciaY.rot= Math.PI/2;
SRicona.aggiungi(asseX);
SRicona.aggiungi(asseY);
SRicona.aggiungi(frecciaX);
SRicona.aggiungi(frecciaY);
SRicona.inSistema(this);
return SRicona;
}
}
Passiamo ad un piccolo esempio
Supponiamo di creare alcuni punti che collegati con linee delimitino il contorno di una casetta. Sono contenuti in un oggetto di tipo gruppo() e viene fatto di quest'ultimo 3 copie. Ogni copia della casetta viene disegnata in un sistema di riferimento diverso: I primi due fissi e il terzo mobile attraverso il mouse
gruppo casetta = new gruppo(); gruppo Gs1=new gruppo(); gruppo Gs2=new gruppo(); gruppo Gs3=new gruppo(); Punto C[] =new Punto[5]; Sistema mio=new Sistema(new Punto(50, 80), Math.PI/6, 1, 1); Sistema uni=new Sistema(new Punto(100, 70), 0, 1, 1);
Nel method init() della classe principale scriviamo:
C[0]= new Punto(20, 20); C[1]= new Punto(30, 20); C[2]= new Punto(30, 30); C[3]= new Punto(20, 30); C[4]= new Punto(25, 10); casetta.aggiungi(new Linea(C[0], C[1])); casetta.aggiungi(new Linea(C[1], C[2])); casetta.aggiungi(new Linea(C[2], C[3])); casetta.aggiungi(new Linea(C[3], C[0])); casetta.aggiungi(new Linea(C[0], C[4])); casetta.aggiungi(new Linea(C[4], C[1]));
Si fanno i cloni dei gruppi per evitare la modifica dei dati originali.
Siamo costretti ad ammettere di non essere riusciti ad usare il metodo clone() perchè questo modifica anche le caratteristiche dell'oggetto originale. Allora è stato implementato in ogni classe entita il metodo clonato() che funziona a meraviglia e ne parleremo forse sempre alla prossima puntata
Gs1 = casetta.clonato(); Gs2 = casetta.clonato();
Qui vengono effettuate le trasfomazioni delle coordinate dei primi due sistemi
Gs1.inSistema(mio); Gs2.inSistema(uni);
Nella Paint() invece scriviamo:
public void paint(Graphics g) {
Dimension d = size(); offg.setColor(Color.white); offg.fillRect(0, 0, d.width, d.height);
il sistema di riferimento mobile viene creato qui perchè dinamico, cioè variabile ad ogni ciclo della Paint() e viene anche clonato e trasformato nel sistema mobile
Sistema mob=new Sistema(pa, new Linea(pa, p).angoloXY(), 1, 1); Gs3 = casetta.clonato(); Gs3.inSistema(mob); Gs1.disegna(Color.blue, offg); Gs2.disegna(Color.red, offg); Gs3.disegna(Color.black, offg); Poi si disegna mio.icona().disegna(Color.blue, offg); uni.icona().disegna(Color.red, offg); mob.icona().disegna(Color.black, offg); ...... }
Provate l'applet!
Le frequenti modifiche alle classi già presentate sono dovute al continuo miglioramento della loro struttura. E da tener presente, inoltre, che tali articoli non sono già belli e confezionati, ma vengono scritti dall'autore di volta in volta.
Basta, comunque, farsi il download dei files newGraphics.java e vectors.java e sostituirli a quelli già downloadati in precedenza.
Buon divertimento!
Domenico De Riso <deriso@infomedia.it>
