MokaByte
Numero 05 - Febbraio 1997
|
|||
|
parte II |
||
Domenico De Riso |
soluzioni temporanee | ||
Dopo l'introduzione
alla grafica vettoriale dello scorso numero finiscono le chiacchiere e
si passa alla pratica con la creazione di nuovi oggetti grafici utilissimi,
per il disegno sulle applet, a coloro che NON vogliono rivedere od imparare
formule matematiche e di geometria analitica, ma vogliono semplicemente
vivere tranquilli e, nello stesso tempo, ricavare da Java le massime potenzialità
di grafica vettoriale.
Dopo uno
sguardo all'overview di Javasoft ho constatato che ci stanno copiando!
Ma non credo siano pronti prima della fine del 1997 (almeno così
hanno "labellato" gli argomenti Java2D e Java3D).
Nell'articolo
precedente è stata sottolineata l'importanza di "aggiustare" alcuni
methods della classe awt.Graphics, come drawOval(...) e drawArc(...), per
il fatto che essi trattano le circonferenze circolari ed ellittiche in
un modo un pò strano.
Dicemmo che
disegnare una circonferenza con il drawOval(...) attuale bisogna prepararsi
a dei "calcoli mentali" e, visto che noi siamo i programmatori e non i
calcolatori o, per dirla in modo fantascientifico, noi siamo i "creativi"
e non i "programmi", il drawOval(...) deve essere bandito.
Vediamo perchè:
drawOval(int
x, int y, int width, int height) non e’ altro che il bounding box
o rettangolo di contenimento di una ciconferenza o di un’ellisse.
Nella vita quotidiana,
quando un programmatore o un disegnatore ha una circonferenza da disegnare,
nel 99% dei casi i dati sono costituiti dalle coordinate del punto centro
e la lunghezza del raggio. Ma nella awt.Graphics NON è
implementato qualcoosa di simile a un drawCircle(int xc, int yc, int
r).
Sempre nell’articolo
precedente fu fatto un esempio pratico per disegnare due circonferenze
concentriche delle quali si conosceva il centro comune (125,103)
e i raggi 28 e 15.
Guardate
cosa bisognerebbe scrivere: drawOval(97, 75, 56, 56) e drawOval(110,
88, 30, 30). Praticamente nessuno dei dati iniziali può essere
passato come parametro, ma solo dopo un calcolo "cervellotico"...
Inoltre non
capisco perché tutti i parametri dei methods grafici sono di tipo
int. Il mio parere è che debbano essere assolutamente di
tipo double o almeno float. Spesso capita di dover disegnare
grafici con coordinate frazionali e comprese tra i numeri intorno allo
zero.
Invece un disCirconf(double
xc, double yc, double r) sarebbe semplice e versatile. Per l’esempio
precedente bisognerebbe solo digitare disCirconf(125, 103, 28) e
disCirconf(125, 103, 15) che sono tutti i dati iniziali.
Anzi, visto
che la nostra disCirconf(...) non deve essere da meno della drawOval(...)
attuale che disegna anche ellissi, è meglio prevedere un methods
private disCircolo(...) e ulteriori methods public che fanno
riferimento al primo a seconda dei casi in cui si debba disegnare poligoni
regolari o ellittici, circonferenze od ellissi.
Prima
creiamo una classe del tipo newGraphics in un file del tipo newGraphics.java,
che conterrà methods sia nuovi che alternativi alla awt.Graphics.
Non voglio dilungarmi
sul fatto che conviene o meno che la newGraphics sia una extends
della awt.Graphics. A questo ci pensate voi dipendentemente dalle circostanze.
A me interessa solo che sia più facile disegnare per cui la newGraphics
sarà contenuta in un file newGraphics.java ed è questa:
La variabile g è quella corrispondente che viene passata dalla Paint. Le variabili xDal, yDal, xAl, yAl sono i valori fisici che le coordinate dei punti assumono per essere fisicamente disegnati. La nostra disCircolo(...) sarà un method private della nuova classe newGraphics:import java.awt.*;
public class newGraphics {
Graphics g;
double xDal=0, yDal=0, xAl, yAl;
newGraphics(Graphics g) {
this.g=g;
}
disCircolo(...) disegna un'ellisse con centro in xc e yc e semiassi ra ed rb. Se si tratta di un Poligono allora sarà di nl lati e se è un poligono regolare potrà essere ruotato di rotz gradi.private void disCircolo(double xc, double yc, double ra, double rb, int nl, double rotz) {
for (double an=rotz; an<=2*Math.PI+rotz+.0001; an+=2*Math.PI/nl) {
xAl = ra*Math.cos(an)+ xc;
yAl = rb*Math.sin(an)+ yc;
if (an>rotz) g.drawLine((int) xDal, (int) yDal, (int) xAl, (int) yAl);
xDal=xAl;
yDal=yAl;
}
}
Ulteriori chiarimenti di geometria analitica sui methods precedenti possono essere richiesti direttamente all'autore in forma privata perchè esulano dall'argomento corrente.// poligono ellittico non ruotato
public void disPoligonoE(double xc, double yc, double ra, double rb, int nl) {
disCircolo(xc, yc, ra, rb, nl, 0);
}
// poligono regolare non ruotato
public void disPoligonoR(double xc, double yc, double r, int nl) {
disCircolo(xc, yc, r, r, nl, 0);
}
// poligono regolare ruotato
public void disPoligonoR(double xc, double yc, double r, int nl, double rotz) {
disCircolo(xc, yc, r, r, nl, rotz);
}
// ellisse
public void disEllisse(double xc, double yc, double ra, double rb) {
disCircolo(xc, yc, ra, rb, 128, 0);
}
// circonferenza con noti centro e raggio
public void disCirconf(double xc, double yc, double r) {
disCircolo(xc, yc, r, r, 128, 0);
}
// circonferenza passante per 3 punti noti
public void disCirconf(double xa, double ya, double xb, double yb, double xc, double yc) {
double m1 = -(xb - xa) / (yb - ya);
double m2 = -(xb - xc) / (yb - yc);
double n1 = ((xb*xb - xa*xa) + (yb*yb - ya*ya)) / 2 / (yb - ya);
double n2 = ((xb*xb - xc*xc) + (yb*yb - yc*yc)) / 2 / (yb - yc);
if (m1 != m2) {
double x = (n2 - n1) / (m1 - m2);
double y = m2 * x + n2;
double r = Math.sqrt((x - xb)*(x - xb) + (y - yb)*(y - yb));
disCircolo(x, y, r, r, 128, 0);
}
else System.out.println("i punti sono allinati");
}
}
Sappiate,
però, che questi methods verranno modificati o abbandonati
perché utili solo alla comprensione di come dovrebbe essere meglio
strutturata la parte grafica di un linguaggio. Successivamente le figure
geometriche disegnate saranno considerate oggetti dell’OOP dai quali trarre
informazioni prima o anche dopo la loro apparizione sullo schermo. Perchè?
Tutti i linguaggi
di programmazione hanno sempre trattato le figure geometriche disegnabili
come eventi che, una volta procurati modifiche nella RAM video, restano
lì finchè un ClearScreen o un Cls li cancella, mentre sarebbe
opportuno che, una volta creata una figura geometrica, essa venisse considerata
come un oggetto. Questo accade nelle applicazioni CAD, ma non nei linguaggi
di programmazione a livello di codice.
Un esempio semplice:
bisogna disegnare una linea che unisce i centri di due circonferenze
C1 e C2 di tipo Circonferenza. Una volta creati
gli oggetti C1 e C2, per disegnare le circonferenza si userà un
methods della classe Circonferenza come disegna(). Dunque C1.disegna()
e C2.disegna() disegnerà le due circonferenze.
Per disegnare
la linea di unione dei centri, invece, esisterà un method di una
classe Linea che creerà una linea tra due oggetti
di tipo Punto(double x, double y) che avrà la forma Linea(Punto
p1, Punto p2) e il suo relativo method disegna(). Allora la
linea L tra i centri sarà new Linea(C1.centro, C2.centro)
e per tracciare tale linea L basta L.disegna().
Ma questo verrà
spiegato nel prossimo articolo.
Per ora accontentiamoci
delle semplici soluzioni temporanee precedenti già abbastanza efficienti.
Non dimenticate di chiudere la newGraphics con:
}Allora per disegnare qualcosa create la vostra applet personale così:
Dal prossimo numero, invece di limitarci a disegnare figure geometriche, cominceremo prima a creare gli oggetti con tale forma di figure geometriche e poi penseremo alla loro "meno importante e semplice" rappresentazione grafica. Infatti è più interessante avere un insieme di oggetti non disegnati, ma interrogabili riguardo le loro caratteristiche, che non una loro immagine statica dalla quale non si può trarre alcuna informazione. Questo sarà un vantaggio enorme perchè ci permetterà di disegnare grafici geometrici con perfezione matematica-geometrica senza utilizzare formule.import java.awt.*;
public class miApplet extends java.applet.Applet {
public void paint(Graphics g) {
newGraphics ng = new newGraphics(g);
// disegna due circonferenze concentriche di raggio 28 e 15 e un ellisse
g.setColor(Color.blue);
ng.disCirconf(125, 103, 28);
ng.disCirconf(125, 103, 15);
ng.disEllisse(125, 103, 60, 25);
// disegna una circonferenza per tre punti
ng.disCirconf(100, 150, 70, 120, 80, 190);
// disegna due dodecagoni ellittici e un ottagono regolare
g.setColor(Color.red);
ng.disPoligonoE(125, 103, 78, 35, 12);
ng.disPoligonoE(125, 103, 35, 78, 12);
ng.disPoligonoR(125, 103, 78, 8);
// disegna un esagono ruotato di PI/16 inscritto in una circonferenza
g.setColor(Color.black);
ng.disPoligonoR(125, 103, 100, 6, Math.PI/16);
ng.disCirconf(125, 103, 100);
}
}
|
||
|
||
MokaByte ricerca
nuovi collaboratori
|
||
|