MokaByte
Numero 06 - Marzo 1997
|
|||
|
(III parte) "parlare" con Java... |
||
Domenico De Riso |
|||
È
ora di prepararsi alla nascita di importanti classi di primitive geometriche
che ci permetteranno di fare cose straordinarie! Cominciamo dalla primitiva
più "primitiva": Il punto.
Sembra che
sul punto non ci sia quasi niente da dire, (ma è solo un puntino!)
e invece no! Il punto è uno dei fondamenti della Geometria
sulla quale si basano tutte le discipline tecniche e scientifiche.
Il
punto, in un piano cartesiano, sembra il solito oggetto caratterizzato
da due numeri che si chiamano coordinate, ma è anche
il risultato di intersezione di due rette qualsiasi. Anzi, le ben
note coordinate di un punto sono esse stesse delle rette. Quando si dice
che un punto P ha le coordinate x=2 e y=3, tali formule
sono equazioni di primo grado, e le equazioni di primo grado, sul
piano cartesiano SONO LINEE RETTE. Dunque il punto P è
individuato tramite l’intersezione della retta x=2 parallela all’asse
y con la retta y=3 parallela all’asse x.
(Per i soli
esperti: chi crede che y=3 non abbia l’aspetto di una equazione
di retta come y=mx+n la immagini come y=0x+3 che è
appunto equivalente a y=3)
Prima di addentrarci
nell’OOP e dialogare con esso bisogna fornire la base di conoscenza
geometrica almeno riguardo ai punti e alle linee. Il resto viene
quasi da solo. Perciò potete sorvolare sulle formule utillizzate
che non sono importanti allo scopo di quanto segue, ma solo per fornire
la base di conoscenza iniziale.
Tutto il codice
presentato in colore nero è contenuto nei files newGraphics.java,
che contiene anche il codice dell'articolo dello scorso numero, e vectors3.java
contenente il codice necessario alle applet visibili in questa pagina.
Cominciamo a costruire una classe Punto che non sia la solita classe di esempio utilizzata per scopi didattici, ma una classe geometrica completa:
Questo è il punto individuato da una coppia di numeri reali dette coordinate:class Punto { double x, y; Punto() { }
Questo è il punto individuato dall’intersezione di due rette qualsiasi:Punto(double x, double y) { this.x=x; this.y=y; }
Questo è il punto individuato dalle rette che hanno come coefficienti angolari m1 ed m2 e come intercette n1 ed n2.Punto(Linea L1, Linea L2) { if (L1.m != L2.m) { if (!Double.isInfinite(L1.m) && !Double.isInfinite(L2.m)) { x=(L2.n - L1.n) / (L1.m - L2.m); y=L2.m * x + L2.n; } else { if (Double.isInfinite(L1.m)) { x=L1.P1.x; y=L2.m*x + L2.n; } if (Double.isInfinite(L2.m)) { x=L2.P1.x; y=L1.m*x + L1.n; } } } else System.out.println("le linee sono parallele"); }
Questo è il punto posto alla distanza ro ed angolo teta relativamente al punto P. Insomma il punto individuato con cordinate polari relative rispetto al punto P.Punto(double m1, double n1, double m2, double n2) { Punto p = new Punto(new Linea(m1, n1), new Linea (m2, n2)); x = p.x; y = p.y; }
Come al solito non darò spiegazioni sulle formule utilizzate perché esulano dall’argomento, ma sono disponibile tramite e-mail private per qualsiasi chiarimento.Punto(Punto P, double ro, double teta) { x=P.x + ro*Math.cos(teta); y=P.y + ro*Math.sin(teta); } }
Quando
"alcuni" infiniti punti si mettono in riga formano una linea. Una
linea è l’insieme di punti tra due punti P1 e P2 detti
estremi della linea stessa.
Dunque una linea
può essere individuata tramite i suoi due punti estremi. Ma una
coppia di punti può avere origine anche dall’intersezione tra una
seconda linea ed una circonferenza o tra due circonferenze.
Ecco la class Linea:
Le variabili m ed n sono elementi caratteristici della linea perché m è il coefficiente angolare della retta passante per P1 e P2 ed n è l’intercetta della stessa retta (l'intercetta è il punto d’intersezione tra la retta passante per P1 e P2 e l’asse delle ordinate che genera un punto di coordinate x=0 e y=n).class Linea { Punto P1, P2; double m, n;
Questa è la linea tra due semplici punti:
Questa è la linea con coefficiente angolare m ed intercetta n:Linea(Punto P1, Punto P2) { this.P1=P1; this.P2=P2; m=deltaY()/deltaX(); n=-m*P1.x + P1.y; }
di seguito vengono presentati alcuni methods della classe Linea che estraggono informazioni utili per il disegnatore:Linea(double m, double n) { this.m=m; this.n=n; P1=new Punto(0, n); if (!Double.isInfinite(m)) P2=new Punto(-n/m, 0); if (m==0) P2=new Punto(1, n); }
Per conoscere la differenza delle ascisse o delle ordinate di P1 e P2 si possono utilizzare i seguenti methods, già utili immediatamente per il calcolo della lunghezza della linea P1P2
Infatti ecco l’utilizzo dei methods precedenti per il calcolo della lunghezza della linea P1P2:double deltaX() { return P2.x - P1.x; } double deltaY() { return P2.y - P1.y; }
Method per il calcolo del punto medio della linea P1P2:double lunghezza() { return Math.sqrt(Math.pow(deltaX(), 2) + Math.pow(deltaY(), 2)); }
Method che ritorna una ulteriore linea da un punto P, esterno alla linea P1P2 e perpendicalare alla stessa P1P2:Punto medio() { return new Punto((P1.x + P2.x)/2, (P1.y + P2.y)/2); }
Method che ritorna una ulteriore linea passante per un punto P, esterno alla linea P1P2 e parallela alla P1P2:Linea perp(Punto p) { if (!Double.isInfinite(m) && (m!=0)) { m2 = -1/m; n2 = -m2*p.x + p.y; x = (n2 - n) / (m - m2); y = m2 * x + n2; Linea lperp = new Linea(p, new Punto(x, y)); lperp.m = m2; lperp.n = n2; return lperp; } else { if (Double.isInfinite(m)) { x = P1.x; y = p.y; Linea lperp = new Linea(p, new Punto(x, y)); if (lperp.P1==lperp.P2) lperp = new Linea(lperp.P1, new Punto(lperp.P1.x+1, lperp.P1.y)); lperp.m = 0; lperp.n = p.y; return lperp; } else { // (m==0) x = p.x; y = P1.y; Linea lperp = new Linea(p, new Punto(x, y)); lperp.m = Double.POSITIVE_INFINITY; lperp.n = Double.POSITIVE_INFINITY; return lperp; } } }
Data una linea, si immagini la retta passante per essa. Il method ritorna una linea che è la proiezione di un'altra linea, passata come parametro, su tale retta:Linea parallela(Punto p) { if (!Double.isInfinite(m)) return new Linea(m, -m*p.x + p.y); else return new Linea(new Punto(p.x, p.y), new Punto(p.x, P1.y)); }
Questo method disegna fisicamente la linea:Linea proiezione(Linea l) { Punto Pl1= new Punto(new Linea(P1, P2), perp(l.P1)); Punto Pl2= new Punto(new Linea(P1, P2), perp(l.P2)); return new Linea(Pl1, Pl2); }
E' necessario introdurre una classe simile a Linea, perchè costituita anch'essa da due punti, ma non è una Linea. Essa rappresenta l'insieme di punti (da 0 a 2 punti) generati dall'intersezione tra circonferenze, parabole, ellissi e linee.void disegna(Color colore, Graphics g) { g.setColor(colore); g.drawLine((int) P1.x, (int) P1.y, (int) P2.x, (int) P2.y); } }
Questi sono i punti generati dall’intersezione tra una linea ed una circonferenza:class duePunti { Punto P1, P2;
Questi sono i punti generati dall’intersezione tra due circonferenze:duePunti(Linea L, Circonferenza C) { double gam=C.centro.x*C.centro.x + C.centro.y*C.centro.y - C.raggio*C.raggio; double a=1 + L.m*L.m; double b=2*(L.m*L.n - C.centro.x - C.centro.y*L.m); double c=L.n*L.n - 2*C.centro.y*L.n + gam; eq2grado sol=new eq2grado(a, b, c); P1=new Punto(sol.s[0], L.m*sol.s[0] + L.n); P2=new Punto(sol.s[1], L.m*sol.s[1] + L.n); }
Questo method converte un duePunti in Linea:duePunti(Circonferenza C1, Circonferenza C2) { double gam1=C1.centro.x*C1.centro.x + C1.centro.y*C1.centro.y - C1.raggio*C1.raggio; double gam2=C2.centro.x*C2.centro.x + C2.centro.y*C2.centro.y - C2.raggio*C2.raggio; double a=2*(C2.centro.x - C1.centro.x); double b=2*(C2.centro.y - C1.centro.y); double c=gam1 - gam2; Linea asrad =new Linea(-a/b, -c/b); duePunti sec =new duePunti(asrad, C1); P1=sec.P1; P2=sec.P2; }
Dopo aver presentato praticamente SOLO poche classi, Punto e Linea (ma classi di classe!) possiamo realizzare un telegrafo...ehm... possiamo realizzare classi di altre primitive geometriche più complesse senza, come si dice in gergo, saper né leggere e né scrivere:Linea linea() { return new Linea(P1, P2); } }
Semplice! Ma il bello non è questo. Il fatto è che una circonferenza può essere individuata anche da soli 3 punti. Noi mica conosciamo le formule di Geometria Analitica per calcolare il centro e il raggio di una circonferenza avendo noti solo 3 punti??? Io NO! Si fa per dire, ma non servono!class Circonferenza { Punto centro=new Punto(); double raggio; Circonferenza(Punto centro, double raggio) { this.centro=centro; this.raggio=raggio; }
Siano Pa,
Pb, Pc 3 punti qualsiasi non allineati.
Si considerino
i segmenti PbPa e PbPc.
Tradotto in Java:
Si considerino gli assi del segmento PbPa e del segmento PbPc. (L’asse del segmento è la retta passante per il punto medio di un segmento e perpendicolare al segmento stesso).Linea PbPa =new Linea(Pb, Pa); Linea PbPc =new Linea(Pb, Pc);
Tradotto in Java:
Se i due assi dei segmenti non sono paralleli allora la loro intersezione rappresenta il centro di una circonferenza.Linea asPbPa =PbPa.perp(PbPa.medio()); Linea asPbPc =PbPc.perp(PbPc.medio());
Tradotto in Java:
Nel numero scorso dicemmo che noi siamo i programmatori e non i calcolatori, dunque i numeri sono roba per computers. Bene! Da oggi cercheremo di evitare anche formule! Così l’OOP di Java diventa come un linguaggio parlato! Guardate di seguito il constructor completo della circonferenza per 3 punti appena descritto e ditemi se riuscite a vedere un solo numero o una sola formula! Non è straordinario? Questo è il confine tra informatica e filosofia (ora ho esagerato!).if (asPbPa.m != asPbPc.m) { centro =new Punto(asPbPa, asPbPc); raggio =new Linea(centro, Pa).lunghezza(); } else System.out.println("i punti sono allinati");
Circonferenza(Punto Pa, Punto Pb, Punto Pc) { Linea PbPa =new Linea(Pb, Pa); Linea PbPc =new Linea(Pb, Pc); Linea asPbPa=PbPa.perp(PbPa.medio()); Linea asPbPc=PbPc.perp(PbPc.medio()); if (asPbPa.m != asPbPc.m) { centro =new Punto(asPbPa, asPbPc); raggio =new Linea(centro, Pa).lunghezza(); } else System.out.println("i punti sono allinati"); }
Un altro spettacolare
method.
I due punti
di tangenza ad una circonferenza possibili da un punto esterno, si realizzano
molto semplicemnte tramite costruzione grafica-geometrica, senza introdurre
alcuna formula. Infatti i punti di tangenza ad una circonferenza C
da un punto esterno P sono DUE, e sono gli stessi punti che risultano
dall'intersezione tra due circonferenze delle quali la seconda è
la circonferenza avente per centro il punto esterno P e per raggio
la distanza tra P e uno dei punti di tangenza. Tale raggio è
ricavabile con teorema di pitagora applicato alla distanza dei centri
e al raggio della circonferenza C che costituiscono l'ipotenusa
e un lato di un triangolo rettangolo (retto nel punto di tangenza):
Come potete osservare neanche qui sono presenti numeri o formule...!duePunti tangente(Punto p) { // distanza tra P e centro di C double pc = new Linea(p, centro).lunghezza(); // lunghezza della tangente double lunLtan = Math.sqrt(pc*pc - raggio*raggio); // intersezione delle circonferenze return new duePunti(new Circonferenza(p, lunLtan), this); }
Disegna la circonferenza utilizzando il semplice method della newGraphics disCirconf(x, y, r):double area() { return Math.PI*raggio*raggio; } double perimetro() { return 2*Math.PI*raggio; }
Inoltre dicemmo che alcuni methods della newGraphics erano solo provvisori. Infatti il disCirconf(x1, y1, x2, y2, x3, y3) che disegnava circonferenze per 3 punti non è più di utilità perché la classe Circonferenza riduce tutto al semplice disCirconf(x, y, r).void disegna(Color colore, Graphics g) { newGraphics ng = new newGraphics(g); g.setColor(colore); ng.disCirconf(centro.x, centro.y, raggio); } }
Alcuni methods delle classi presentate fanno uso di una classe eq2grado. Essa semplicemente risolve un'equazione di secondo grado i cui coefficienti sono a b c. Le soluzioni trovate vengono conservate nell'array S. Chi non è pratico di equazioni la consideri come una "scatola nera". La classe è questa:
class eq2grado { double a, b, c; double[] s= new double[2]; eq2grado(double a, double b, double c) { this.a=a; this.b=b; this.c=c; double delta=b*b - 4*a*c; if (delta>=0) { s[0]=(-b + Math.sqrt(delta)) / (2*a); s[1]=(-b - Math.sqrt(delta)) / (2*a); } else System.out.println("non esiste un'intersezione reale"); } }
|
||
|
||
MokaByte ricerca
nuovi collaboratori
|
||
|