MokaByte Numero 09 - Giugno 1997

Grafica vettoriale in Java 

 

di  

Domenico De Riso
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!

// 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! 
 
 

 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi puņ farlo scrivendo a mokainfo@mokabyte.it