APPLET DI ESEMPIO: Epiclicloide ed Ipocicloide
La settimana scorsa è venuto a trovarmi un caro amico che lavora al Dipartimento di Fisica Sperimentale di Torino, Ciro Marino, e mi ha chiesto se avessi potuto realizzare una piccola simulazione in Java di un epicicloide o ipocicloide...!? Mi ha detto: «Magari puoi inserirla nei tuoi articoli...» Allora ho replicato: «E cos'e'? Un nuovo tipo di bicicletta?». In realtà mi ricordavo di aver sentito parlare di questi "aggeggi" ai primi anni di Ingegneria, poi mi ha detto: «Noo-o, sono delle funzioni per calcolare le curvature dei denti degli ingranaggi». E mi ha lanciato sulla scrivania un foglietto pieno di formule tra le quali si intravedeva un sistema di due equazioni in tre incognite... Ho detto: «scusa... e la terza incognita? Come la calcolo?». E lui: «Niente di straordinario, sono equazioni parametriche...». Allora ho risposto: «Mi dispiace, nei miei articoli su Java non uso formule!». E lui: «non lasciarti impressionare dalle formule, un epiclicloide graficamente non è altro che la traccia di un punto posto su una circonferenza, rotante a sua volta su un'altra circonferenza».
Infatti gli archetti che costituiscono i denti delle ruote dentate di un ingranaggio, nel piccolo tratto di ogni dente, hanno proprio la forma della traccia sopra citata. Se così non fosse si avrebbero degli attriti enormi tra i denti.
«Ahhh! E allora e' semplice. Lo posso fare in Java usando la libreria di class e methods che abbiamo creato negli articoli di MokaByte e il foglietto tienitelo pure! Non mi serve!».
Ecco il codice dell'applet: dopo tre giri della circonferenza piccola su quella grande appare il disegno di una ruota dentata!
// centro del sistema
Punto P1 =new Punto(112, 125);
// creazione circonferenza A
Circonferenza A =new Circonferenza(P1, 70);
// creazione corconferenza B
Circonferenza B =new Circonferenza(P1.relativo(A.raggio+15, 0), 15);
// linea-raggio di B utile alla visualizzazione della rotazione
Linea lB =new Linea(P1.relativo(A.raggio+15, 0), P1.relativo(A.raggio,
0));
// creazione del gruppo
gruppo gr3= new gruppo(Color.red);
// aggiunge B al gruppo
gr3.aggiungi(B);
// aggiunge la linea-raggio al gruppo
gr3.aggiungi(lB);
// ruota il gruppo intorno al centro di B
gr3.ruota(B.centro, Math.PI/32);
// e poi il tutto intorno al centro di A
gr3.ruota(A.centro, B.raggio/A.raggio*Math.PI/32);
// poi si disegna il tutto
A.disegna(Color.blue, offg);
gr3.disegna(offg);
lB.disegna(Color.magenta, offg);
lB.P2.relativo(d.width/2, 0).disegna(Color.black, g);
offg.drawString("P", (int) lB.P2.x, (int) lB.P2.y);
Come al solito non ci sono formule. Dobbiamo solo esprimere in Java ciò che si desidera fare.
E' un pò come andare in aereo da Napoli a Roma. Ci si impiega 25 minuti dei quali 10 per il decollo, 10 per l'atterraggio e 5 per il viaggio! Così quest'applet è costituita da 14 righe delle quali 7 per la dichiarazione degli oggetti, 5 per disegnare e solo 2 per il nocciolo della questione!
Ora passiamo alla presentazione di una nuova classe:
POLIGONI REGOLARI
Qualche filosofo affermerebbe che i poligoni sono come una specie di circonferenze "embrionali"!, cioe' sono circonfrenze non ancora sviluppate! In fondo quando si visualizzano circonferenze a video, tramite programmi grafici, sono SEMPRE approssimate. Dunque sono poligoni. Al massimo si può (e si deve) cercare di "accordare" il numero di pixel della grafica in uso con il numero di lati massimi da attribuire al poligono. Insomma se una circonferenza, lungo la quale si contano almeno 200 pixel, viene visualizzata su uno schermo, conviene disegnare un poligono con non piu' di 200 lati. Altrimenti si perde solo tempo di elaborazione e si può perdere anche in nitidezza di immagine della circonferenza stessa. Questo perchè alcuni lati del poligono potrebbero essere disegnati (per motivi di approssimazione di calcolo del computer) su pixel adiacenti con il risultato di una brutta rappresentazione.
Se invece si disegnano meno lati del previsto allora la circonferenza comincia a perdere la sua rotondità e diventa sempre più simile ad un poligono.
Su uno schermo di 14" con una risoluzione di 1024x768 punti, una circonferenza che rientra tutta nello schemo può essere benissimo disegnata come un poligono con una duecentina di lati.
Il method disegna() della class Circonferenza che abbiamo introdotto nei primi articoli richiama il method disCirconf() che a sua volta richiama disCircolo() con il parametro nl (numero lati) impostato a 128. Bastano infatti 128 lati affinchè una circonferenza appaia alquanto rotonda in una finestra di applet. In ogni caso è modificabile. A dir il vero, e ad essere proprio precisi, questo parametro dovrebbe essere dinamico, cioè dovrebbe variare al variare del raggio della circonferenza. Di questo tratteremo in articoli più specifici, magari in futuro, quando con le basi di conoscenza che stiamo fornendo si potrà realizzare un miniCAD.
Perciò saper programmare poligoni serve soprattutto a costruire una buona base di conoscenza utile alla programmazione per disegnare circonferenze.
Il disegno di poligoni da parte di programmi avviene sempre con l'uso di funzioni trigonometriche. Questo perchè è il modo più semplice per generare qualcosa di circolare, essendo tale disciplina, la trigonometria, basata proprio sullo studio degli angoli e dei triangoli. E i triangoli non sono altro che i poligoni aventi il minimo numero di lati.
La class Poligono è questa:
class Poligono extends
entita {
// gli elementi che caratterizzano un poligono
sono il centro e il raggio, la lunghezza del lato, il numero di lati
Punto centro=new
Punto();
double raggio, lato, rot;
int numLati;
// poligono con numero lati noto inscritto nella
circonferenza con centro e raggio specificati
Poligono(Punto
centro, double raggio, int numLati) {
this.centro=centro;
this.raggio=raggio;
lato=2*raggio*Math.sin(4*Math.PI/numLati);
this.numLati=numLati;
rot=0;
}
// poligono inscritto nella circonferenza passante
per tre punti noti e noto il numero di lati
Poligono(Punto Pa,
Punto Pb, Punto Pc, int numLati) {
Linea Lba =new Linea(Pb, Pa);
Linea Lbc =new Linea(Pb, Pc);
Linea asLba=Lba.perp(Lba.medio());
Linea asLbc=Lbc.perp(Lbc.medio());
if (asLba.m != asLbc.m) {
centro =new Punto(asLba, asLbc);
raggio =new Linea(centro, Pa).lunghezza();
this.numLati=numLati;
lato=2*raggio*Math.sin(4*Math.PI/numLati);
rot=0;
}
else System.out.println("i punti sono
allinati");
}
Questo method è molto interessante perchè permette di disegnare un poligono in un modo inusuale. Infatti basta siano noti solo i due punti estremi di un lato e il numero di lati desiderati. Il programma calcola automaticamente la posizione del centro, il raggio e la rotazione del poligono nell'ambito del piano cartesiano XY.
Per verificarlo provate l'applet a fianco. Vengono visualizzati poligoni con numero sempre cerscenti di lati... e poi riparte da tre.
Questa applet usa il constructor descritto di seguito e, solo per la costruzione geometrica visiva dell'applet di fianco applica i methods del calcolo del poligono circoscritto() che richiama quello del poligono parallelo() che a sua volta richiama il calcolo dell'apotema()(solo in vectors5.java).
// poligono con noti solo i punti estremi
di un lato e il numero dei lati
Poligono(Punto P1,
Punto P2, int numLati, boolean unodeidue) {
this.numLati = numLati;
lato = new Linea(P1, P2).lunghezza();
raggio = lato/(2*Math.sin(Math.PI/numLati));
Circonferenza C1 =new Circonferenza(P1, raggio);
Circonferenza C2 =new Circonferenza(P2, raggio);
duePunti centri =new duePunti(C1, C2);
if (!unodeidue) {
centro = centri.P1;
rot =new Linea(centro, P1).angoloXY();
}
else {
centro = centri.P2;
rot =new Linea(centro, P2).angoloXY();
}
}
// area del poligono
double area()
{
return perimetro()*apotema()/2;
}
// perimetro del poligono
double
perimetro() {
return lato*numLati;
}
// apotema del poligono
double apotema() {
return Math.sqrt(raggio*raggio - lato*lato/4);
}
// poligono parallelo ad una distanza nota dai lati del poligono in corso
Poligono
parallelo(double d) {
Poligono plgpar = new Poligono(centro,
(apotema()+d)*raggio/apotema(), numLati);
plgpar.rot=rot;
return plgpar;
}
// poligono cirscoscritto al cerchio in cui il
poligono corrente e' inscritto
Poligono
circoscritto() {
return parallelo(raggio - apotema());
}
// sposta il poligono
parallelamente allo spostamento Porig - Pdest
void sposta(Punto
Porig, Punto Pdest) {
centro.sposta(Porig, Pdest);
}
// ruota di un anglo
specificato il poligono intorno ad un punto
void ruota(Punto
Prot, double alfa) {
centro.ruota(Prot, alfa);
}
// disegna il poligono
void disegna(Color
colore, Graphics g) {
newGraphics ng = new newGraphics(g);
g.setColor(colore);
ng.disPoligonoR(centro.x, centro.y, raggio, numLati, rot);
}
}
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 vectors5.java e sostituirli a quelli già downloadati in precedenza.
Buon divertimento!
