La Rhodonea (aka rosa di Grandi)
Il mio primo articolo è sul mio secondo progetto realizzato in Flash CS3.
Qualcuno forse obbietterà che sarebbe stato meglio cominciare con il mio primo progetto, così avrei potuto far notare in quali difficoltà si può incorrere durante la migrazione da flash8 o ancora avrei potuto mostrare come porsi dinanzi al programma dal punto di vista di un nuovo utente.
Ma non farò così. C’ teng’ a vrè?!
Allora la Rhodonea.
Innanzitutto cos’è una rhodonea? Domanda legittima, tant’è che fino a un paio di giorni fa non ne sapevo niente neanch’io.
Mi ci sono imbattuto casualmente su Wikipedia mentre cercavo qualcosa a proposito delle forze armoniche smorzate…
qui c’è il link su wikipedia.
Scopriamo quindi questo bel fiorellino matematico (quanto mi piacciono i fiorellini matematici
)
Allora, su wiki leggiamo che la sua equazione polare è ρ=R sin ωθ e in piu che se ω è una frazione del tipo n/d con n e d interi positivi non nulli si ottengono le piacevolissime figure riportate sempre su wiki (e linkate qua sotto)

Veniamo a Flash ora.
Allora per prima cosa costruiamo una struttura di directory adatta al sistema di package di flash, molto similmente a quanto faremmo in java, o meglio fareste, visto e considerato che io in java ho sviluppato al momento troppo poco per fare paragoni di sorta (anche se imho ce ne sarebbero molti).
quindi ho creato la cartella org con all’interno altre due cartelle: Main e Geometria. Da tenere presente che cambiando tale struttura il codice che segue si rifiuterà, ovviamente, di funzionare (e credo che la faccenda sia anche case-sensitive).
Apriamo quindi Flash.
A questo punto mi sento di consigliare di creare un nuovo progetto (file .flp) allo scopo di poter tenere sott’occhio tutti i file di cui avremo bisogno (in questo caso saranno solo 3, ma è meglio ragionare in prospettiva no?!). E’ molto probabile che il file di progetto fornisca anche altre possibilità, ma al momento lo ignoro.
Il primo file di cui avremo bisogno è ovviamente un bel .fla. Creiamone uno e associamolo al progetto (nell’apposito pannello), il nome di questo file sceglietelo come più vi aggrada, basta che lo inseriate nella stessa cartella dove avete messo la cartella org.
Ora, visto che siamo dei fraccomodi apriamo il pannello dei Componenti e piazziamo sullo stage:
3 Slider (istanziati come: raggio_g, n_g, d_g)
aggiungendo magari 3 etichette, rispettivamente: raggio, n, d
2 Button (istanziati come: start_bt, stop_bt)
settando magari le loro label rispettivamente: start,stop
1 ColorPicker (istanziato come: line_pic)
ora nella cartella org->Main creiamo un file di testo e chiamiamolo RhodoneaMain.as. A questo punto nel panello Proprietà del file .fla, nel campo Document Class inseriamo org.Main.RhodoneaMain.
Invertendo l’ordine delle operazioni flash protesterà perchè non avete ancora creato il file, ma non è un problema.
La Document Class è la classe che contiene il main del nostro progetto, costituito in particolare dal suo costruttore.
No, non spiegherò cos’è un costruttore visto che questo non è un articolo sulla programmazione a oggetti. Per chi non lo sapesse e non volesse approfondire l’argomento sconsiglio di proseguire visto la struttura fortemente orientata agli oggetti di AS3.0.
L’unica cosa da notare è che questo oggetto deve derivare dalla classe MovieClip (o da Sprite da cui deriva MovieClip);
Apriamo dunque il file RhodoneaMain.as:
Esaminiamo passo passo il codice. Alla prima riga troviamo:
package org.Main{
questo è il package a cui accennavo e dove ovviamente org e Main sono i nomi delle cartelle che abbiamo creato prima.
import flash.display.MovieClip;
import flash.events.*;
import fl.events.ColorPickerEvent;
import org.Geometria.*;
qui importiamo alcune classi e alcuni package. Nello specifico la prima riga importa la definizione della classe MovieClip, la seconda l’intero package relativo agli events, la terza i soli eventi del ColorPicker mentre l’ultima importa tutto il nostro package Geometria (cioè tutti i file nella cartella Geometria).
public class RhodoneaMain extends MovieClip {
a questo punto dichiariamo la nostra classe, il cui nome deve essere uguale al nome del file che la contiene e che come abbiamo detto deve derivare (extendere) la classe MovieClip.
private var r:Rhodonea=null;;
private var lineColor:uint=0
definiamo quindi 2 attributi per il nostro oggetto RhodoneaMain.
r sarà un’istanza del nostro oggetto Rhodonea, mentre lineColor rappresenta il colore con cui disegneremo il nostro fiore.
public function RhodoneaMain() {
line_pic.addEventListener(ColorPickerEvent.CHANGE, colorLine);
start_bt.addEventListener(MouseEvent.CLICK,start_func);
stop_bt.addEventListener(MouseEvent.CLICK,stop_func);
}
Questo è il famoso costruttore della classe RhodoneaMain e che come detto rappresenta il main del nostro programma (sic!). Il codice presente qui viene eseguito all’avvio del progetto.
Nello specifico qui si associano 3 listeners a 3 degli oggetti presenti sullo stage. La gestione degli eventi meriterebbe sicuramente una trattazione molto più approfondita, ma se la cosa vi suona completamente nuova (ari-sic!) vi basti capire che, ad esempio, all’evento di click del mouse (MouseEvent.CLICK) sul bottone start (start_bt) verrà eseguita la funzione registrata start_func. Allo stesso modo registriamo la funzione stop_func per il click sul bottone stop_bt e la funzione colorLine al cambio di colore nel ColorPiker.
Vediamo dunque queste tre funzioni:
private function start_func(event:Event) {
if (r!=null) {
removeChild(r);
}
r=new Rhodonea(raggio_g.value,n_g.value,d_g.value);
r.setColor(lineColor);
r.x=stage.stageWidth/2;
r.y=stage.stageHeight/2-50;
addChild(r);
r.disegna();
}
Questa è la funzione che verrà eseguita alla pressione del bottone start_bt e che avvia il tutto. il suo comportamento è elementare: si controlla che l’istanza r della Rhodonea sia diverso da null, nel qual caso la rimuoviamo (così da cancellare l’eventuale disegno precedente). Istanziamo quindi una nuova Rhodonea con i tre parametri settati dai 3 Slider. Utilizziamo il metodo setColor() dell’oggetto Rhodonea per attribuirgli il colore da utilizzare (nel caso non sia stato selezionato nessun colore nel ColorPicker l’attributo lineColor è stato inizializzato a 0 , cioè nero).
A questo punto centriamo la Rhodonea r sullo stage come fosse un normalissimo MovieClip (vedremo infatti che anche l’oggetto Rhodonea deriva da MovieClip). A questo punto vorrei fare una piccola parentesi: infatti a partire da AS3.0 non è più possibile utilizare metodi tipo attachMovie per aggiungere clip allo stage, basterà infatti una semplice chiamata ad addChild e non dovremo più settare profondità, nome di istanza nè nulla, di tutto si occuperà addChild
l’ultima riga chiama il metodo disegna() dell’oggetto Rhodonea che eseguirà tutto il lavoro di disegno appunto.
private function stop_func(event:Event):void {
r.stoppa();
}
questa è la funzione associata al bottone stop e non fa altro che chiamare il metodo stoppa() della classe Rhodonea che si occuperà di fermare l’operazione di disegno.
private function colorLine(e:ColorPickerEvent):void {
var cp:ColorPicker = e.target as ColorPicker;
lineColor=cp.selectedColor;
}
infine la funzione associata al ColorPicker che recupera l’istanza che ha causato l’evento (cioè il ColorPicker stesso) e associa all’attributo lineColor il colore selezionato da questa.
Passiamo quindi ad analizzare il cuore del nostro progetto: la classe Rhodonea.
Tralasciamo la parte relativa al package e all’importazione dei package nativi di flash in quanto valgono le stesse considerazioni relative al file precedentemente analizzato. Passiamo quindi direttamente alla definizione della classe e ai sui attributi:
public class Rhodonea extends MovieClip {
private var R:Number;
private var omega:Number;
private var teta:Number=0;
private var old,current:Point=null;
private var n,d:Number;
private var lineColor:uint=0;
come accennato prima anche la classe Rhodonea deriva da MovieClip, del resto contiene il nostro disegno e in questo modo la potremo visualizzare sullo stage. Seguono alcuni attributi caratterizzanti la Rhodonea stessa: cioè il raggio (r), omega (il rapporto n/d, ricordate cosa c’era scritto sulla pagina di wiki?), teta (il parametro indipendente della funzione che calcola la rhodonea), i 2 punti (Point) current e old utilizzati per i singoli segmenti della rhodonea e lineColor che è il colore con cui disegneremo il fiore (inizializzato a 0 cioè nero).
public function Rhodonea(R_:Number,n_:Number,d_:Number) {
R=R_;
n=n_;
d=d_;
omega=n_/d_;
}
Il costruttore non fa altro che acquisire i parametri, calcolare il rapporto omega=n/d e associare il tutto agli attributi dell’oggetto.
public function disegna():void {
addEventListener(Event.ENTER_FRAME,disegna_);
}
la proprietà disegna() non fa altro che associare il metodo privato disegna_() all’evento ENTER_FRAME, in pratica quindi questo metodo verrà richiamato continuamente (il numero di FPS si può settare nelle proprietà del documento .fla).
public function stoppa():void {
removeEventListener(Event.ENTER_FRAME,disegna_);
}
stoppa() rimuove l’eventlistener definito nella funzione precedente causando la fine dell’operazione di disegno.
public function setColor(col:uint){
lineColor=col;
}
questo metodo setta l’attributo lineColor che definisce il colore della linea
private function f(ics:Number):Number {
return R * Math.cos(omega * teta);
}
questa E’ la funzione della rhodonea, pari pari a come sta su wiki
private function disegna_(event:Event):void {
current=new Point();
var effe:Number=f(teta);
current.x=effe*Math.cos(teta);
current.y=effe*Math.sin(teta);
if (old!=null) {
var linea:Shape=new Shape();
linea.graphics.lineStyle(0,lineColor);
linea.graphics.moveTo(old.x,old.y);
linea.graphics.lineTo(current.x,current.y);
addChild(linea);
}
old=current;
teta=(teta+0.1);
if (teta>(Math.PI*d*n)+1) {
removeEventListener(Event.ENTER_FRAME,disegna_);
}
current=null;
}
la funzione disegna_() viene quindi richiamata continuativamente dopo la pressione del tasto start_bt. Il funzionamento è molto semplice: in pratica disegna un segmento tra due punti:old e current. A questo fine inizializza il punto current e calcola la variabile effe tramite il metodo f(teta), in modo da avere in tale variabile il valore della distanza della prossima coordinata polare della rhodonea (il parametro angolare è teta). Si trasforma quindi la coordinata polare in cartesiana e si ottengono quindi le coordinate x e y del punto current.
A questo punto si controlla che il punto old sia valido (questo non avviene solo alla prima iterazione) e in quel caso si istanzia un oggetto Shape che costituirà il prossimo segmento da disegnare, lo utilizziamo infatti per tracciare una linea dal punto old al punto current.
Fatto ciò quello che era il punto current diventa quello old e si incrementa il parametro teta di 0.1 al fine di calcolare, alla prossima iterazione la prossima coordinata polare della rhodonea.
A questo punto ho aggiunto un controllo sulla dimensione di teta, visto che il disegno della rhodonea è periodico, cioè dopo un certo numero di iterazioni i valori si ripetono uguali, purtroppo non sono riuscito a trovare una formula esatta per il calcolo di tale periodo, ma ho notato che dovrebbe essere in funzione di n e d. Ad ogni modo il limite che ho impostato è quasi sempre sufficiente.
bhè questo è tutto. divertitevi.
e qui ci sono tutti i sorgenti
