MokaByte Numero 09 - Giugno 1997 |
|||
|
Grafica vettoriale in Java |
||
di |
Poligoni regolari | ||
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!
Come al solito non ci sono formule. Dobbiamo solo esprimere in Java ciò che si desidera fare.// 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);
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 latiPunto centro=new Punto();
// poligono con numero lati noto inscritto nella circonferenza con centro e raggio specificati
double raggio, lato, rot;
int numLati;Poligono(Punto centro, double raggio, int numLati) {
// poligono inscritto nella circonferenza passante per tre punti noti e noto il numero di lati
this.centro=centro;
this.raggio=raggio;
lato=2*raggio*Math.sin(4*Math.PI/numLati);
this.numLati=numLati;
rot=0;
}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).
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.// poligono con noti solo i punti estremi di un lato e il numero dei lati
Poligono(Punto P1, Punto P2, int numLati, boolean unodeidue) {
// area del poligono
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();
}
}double area() {
return perimetro()*apotema()/2;
}
// perimetro del poligonodouble 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 corsoPoligono parallelo(double d) {
// poligono cirscoscritto al cerchio in cui il poligono corrente e' inscritto
Poligono plgpar = new Poligono(centro, (apotema()+d)*raggio/apotema(), numLati);
plgpar.rot=rot;
return plgpar;
}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 poligonovoid disegna(Color colore, Graphics g) {
newGraphics ng = new newGraphics(g);
g.setColor(colore);
ng.disPoligonoR(centro.x, centro.y, raggio, numLati, rot);
}
}
|
||
|
||
MokaByte
rivista web su Java |
||
|