Programmazione

Sezione sulla programmazione Object Oriented in C++, C#, e Java

Simulazione Dinamica dei Fluidi in 2D

Questo programma simula la dinamica di un fluido non comprimibile. Nel Fluido agiscono delle forze di velocità (implementate da un campo di flusso) che alimentano delle correnti interne al fluido. Tali forze possono essere generate dall'utente muovendo il mouse nel fluido o da degli emettitori che possono essere aggiunti a piacere dall'utente.

Il simulatore, (ancora in pre beta e verrà aggiornato) mostra l'effetto che le correnti hanno su un colorante che l'utente può aggiungere nel fluido e vederlo diluirsi e spostarsi nel fluido in funzione della densità, della viscosità e di altre caratteristiche.

Ho scritto sia il codice della simulazione che traduce il modello matematico (i link ai modelli matematici e agli articoli scientifici usati sono in coda a questo post) in un algoritmo funzionante scritto in Java e eseguibile anche direttamente sul web (vedi seguito per usare il simulatore direttamente nel browser)

Ho implementato anche il codice per consentire all'utente di interaggire con la simulazione usando sia il mouse che comandi testuali. A tal scopo ho creato una classe apposita che implementa una console testuale che può essere anche usata in altri progetti (in seguito farò un post solo per la console).

Ho inoltre implementato anche diversi dipi di renderizzatori, usando il polimorfismo del linguaggio Java ho progettato una interfaccia RenderizzatoreFluido che le classi che vogliono renderizzare il fluido devono implementare (vale lo stesso anche per i ModificatoriFluido). Quelle che ho creato consentono di disegnare:

1) il colorante che si diluisce nel fluido animandosi seguendo le correnti generate sia dall'utente che da emettitori draggabbili

2)le correnti stesse sotto forma di vettori orientati nel verso della velocità del campi di fluisso che governa il fluido

2.5)le correnti visualizzate in modo raster dove il colore giallo è il massimo della velocita, e miscelazioni di colore particolari rendono graficamente l'effetto delle onde di propagazione delle forze nel fluido

3)un renderizzatore artistico mostra il colorante sotto forma di retino

Il programma è scritto in Java e di seguito potete usarne una versione per il web e in coda trovate il listato completo.

Clicca nella immaggine sottostante per fare il focus al programma.

 

USO:

  • Muovi il mouse tenendo premuto il tasto destro per aggiungere colorante.
  • Muovi il mouse tenendo premuto il tasto sinistro per aggiungere velocita e miscelare il colorante nel fluido.
  • Premi c Per aprire la console testuale

I comandi della console sono i seguenti: 

man (apre la guida) close man (la chiude)

dens //disenga le densità del colorante

vel vet //disegna le velocità come vettori di direzione

vel sfum //disegna le velocità come sfumature di colore

ret //disegna un retino artistico

color //aggiunge un emettitore colore in posizione casuale

force //aggiunge un emettitore di forza basata sul perlinNoise

vortice //aggiunge un emettitore circolare per creare un vortice

author //mostra informazioni sull'autore

close console //chiude la console

esempio per visualizzare le velocità come vettori digita:

vel vet 

e poi premi INVIO

Per disattivare il renderizzatore ridigita vel vet 

 

NOTA: i renderizzatori vengono applicati in pila uno sull'altro quindi se ad esempio hai digitato dens e poi vel sfum il renderizzatore dens non si vedra perché starà sotto. L'ordine ideale per i renderizzatori è il seguente: dens poi vel sfum e sopra a tutti vel vet

 Guida sugli emettiroti colore (comando: color), velocità (comando: force) e vortice (comando: vortice).

Questi emettitori possono essere manipolati con il mouse dopo essere stati aggiunti. Potete spostarli con il mouse usando il pulsante sinistro e potete ridimensionarli usando il pulsante destro (decrementa)<----->(incrementa).

L'emettitore colore incorpora già un emettitore forza lineare che viene abilitato se fai click sul colore e poi orienti il getto in una direzione.

L'emettitore forza usa il PerlinNoise per creare una movimento non lineare delle correnti emesse.

L'emettitore vortice crea una emettitore di forze circolari orientate verso il centro dell'emettitore che generano un effetto vortice, puoi ridimensionalro con il mouse e maggiore è il raggio maggiore è la forza attrattiva.

Alcuni ritagli schermata del programma.

simFluid2

simFluid3

vortice11

 

 

 

 

 

 

 

Guarda un video tutorial su come si usa il simulatore:  Avvia Video

 

Codice Sorgente:  

FluidSimulation:

public class FluidSimulation implements Gi_ConsoleObserver{
public Fluido f;
Console console;
int iterazioni;
public ArrayList<DisegnatoreFluido> disegnatori=new ArrayList<DisegnatoreFluido>();
public ArrayList<AggiornatoreFluido> aggiornatori=new ArrayList<AggiornatoreFluido>();
DisegnatoreDensitaFluido disegnatoreDensita;
DisegnatoreRetinoFluido disegnatoreRetino;
DisegnatoreVelocitaFluido disegnatoreVelocitaVettoriali;
DisegnatoreVelocitaSfumateFluido disegnatoreVelocitaSfumate;
public ArrayList<String> log=new ArrayList<String>();
boolean apriGuida=false;
public FluidSimulation(float dt,float diffusione,float viscosita,int size,int scala,int iterazioni){
f=new Fluido( dt, diffusione, viscosita, size,scala);
this.iterazioni=iterazioni;
disegnatori.add((disegnatoreDensita=new DisegnatoreDensitaFluido()));
aggiornatori.add(new MousePaint());
aggiornatori.add(new EmettitoreColorante((size*scala)/2,(size*scala)/2));
aggiornatori.add(new EmettitoreForza((size*scala)/2,(size*scala)/2));
disegnatoreRetino=new DisegnatoreRetinoFluido();
disegnatoreVelocitaVettoriali=new DisegnatoreVelocitaFluido();
disegnatoreVelocitaSfumate=new DisegnatoreVelocitaSfumateFluido();
console=new Console(10,size*scala-12*13,12,10);
console.addObserver(this);
}
public void nextStep(){
f.step(iterazioni);
}
public String getName(){
return "Simulation";
}
public void disegna(){
for(DisegnatoreFluido d : disegnatori){
f.disegna(d);
}
for(AggiornatoreFluido a : aggiornatori){
f.aggiorna(a);
}
this.nextStep();
drawHelp();
}
public String analizzaComando(String command){
String messageForUser=null;
if(command.equals("ret")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreRetino)){
disegnatori.remove(disegnatoreRetino);
messageForUser="render retino rimosso retype ret per aggiungerlo";
}else{
disegnatori.add(disegnatoreRetino);
messageForUser="render retino aggiunto retype ret per rimuoverlo";
}
}else if(command.equals("vel vet")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreVelocitaVettoriali)){
disegnatori.remove(disegnatoreVelocitaVettoriali);
messageForUser="render velocità rimosso retype vel per aggiungerlo";
}else{
disegnatori.add(disegnatoreVelocitaVettoriali);
messageForUser="render velocità aggiunto retype vel per rimuoverlo";
}
}else if(command.equals("vel sfum")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreVelocitaSfumate)){
disegnatori.remove(disegnatoreVelocitaSfumate);
messageForUser="render velocità rimosso retype vel sfum per aggiungerlo";
}else{
disegnatori.add(disegnatoreVelocitaSfumate);
messageForUser="render velocità aggiunto retype vel sfum per rimuoverlo";
}
}else if(command.equals("dens")){
//esegui il codice del comando localmente
if(disegnatori.contains(disegnatoreDensita)){
disegnatori.remove(disegnatoreDensita);
messageForUser="render densità rimosso retype dens per aggiungerlo";
}else{
disegnatori.add(disegnatoreDensita);
messageForUser="render densità aggiunto retype dens per rimuoverlo";
}
}else if(command.equals("color")){
int x=int(random(1,width-1));
int y=int(random(1,height-1));
messageForUser="Emettitore aggiunto in pos("+x+":"+y+") usa il mouse per spostarlo/ridimensionarlo/orientarlo";
//esegui il codice del comando localmente
aggiornatori.add(new EmettitoreColorante(x,y));
}else if(command.equals("force")){
int x=int(random(1,width-1));
int y=int(random(1,height-1));
messageForUser="Emettitore aggiunto in pos("+x+":"+y+") usa il mouse per spostarlo";
//esegui il codice del comando localmente
aggiornatori.add(new EmettitoreForza(x,y));
}else if(command.equals("close console")){
messageForUser="command ok. Console closing.";
//esegui il codice del comando localmente
console.deactivate();
apriGuida=false;
}else if(command.equals("man")){
messageForUser="Guida aperta. type close man per chiuderla";
//esegui il codice del comando localmente
//console.deactivate();
apriGuida=true;
//drawHelp(apriGuida);
}else if(command.equals("close man")){
messageForUser="command ok. Guida chiusa";
//esegui il codice del comando localmente
//console.deactivate();
apriGuida=false;
//drawHelp(apriGuida);
}
return messageForUser;
}
public void elabKey(char key,int keyCode){
console.elabKey(key,keyCode);
}
public void drawHelp(){
int x=1;
int y=10;
int alt=16;
pushStyle();
fill(0,0,0);
text("press c for open console and type: man for open manual",x,y);
if(key=='c'){
console.activate();
}
if(apriGuida){
pushStyle();
noStroke();
fill(0,0,255,100);
rect(x,y,500,alt*12,5,5,5,5);
fill(255,255,255);
text("Manuale Comandi Simulazione:",x,y+=alt);
text("Usa Mouse: trascina con PULSANTE DESTRO per aggiungere COLORE nel fluido",x,y+=alt);
text("Usa Mouse: trascina con PULSANTE SINISTRO per aggiungere FORZA nel fluido",x,y+=alt);
text("COMANDI TESTUALI:",x,y+=alt);
text("> close man [INVIO] chiudi la guida",x,y+=alt);
text("> close console [INVIO] chiudi console",x,y+=alt);
text("> vel vet [INVIO] abilita/disabilita renderizzatore velocità vettoriali",x,y+=alt);
text("> vel sfum [INVIO] abilita/disabilita renderizzatore velocità raster",x,y+=alt);
text("> dens [INVIO] abilita/disabilita renderizzatore densità colorante",x,y+=alt);
text("> ret [INVIO] abilita/disabilita renderizzatore artistico tipo retino",x,y+=alt);
text("> color [INVIO] aggiunge un emettitore di colori",x,y+=alt);
text("> force [INVIO] aggiunge un amettitore di forza",x,y+=alt);
text("Programmato da: GiuseppeGi < www.giuseppegi.it >",x,y+=alt);
popStyle();
}
popStyle();
console.display();
}
}

Altre classi che ho scritto il cui codice è disponibile su richiesta contattandomi:

Gi.Console

Gi.ConsoleOBserver

Gi.MouseGUI

Gi.MousePaint

Gi.EmettitoreColorante

Gi.EmettitoreForza

Gi.Fluido

Gi.DisegnatoreVelocitaSfumateFluido

Gi.DisegnatoreDensitaFluido

Gi.DisegnatoreRetinoFluido

Gi.Main

 

Modelli Matematici e riferimenti e riconoscimenti per lavori di ricerca su cui si basa la mia implementazione

Navier–Stokes equations

https://en.wikipedia.org/wiki/Navier%E2%80%93Stokes_equations

Jos Stam, "Fluidi stabili", SIGGRAPH 1999: Atti di conferenza di 
Navier-Stokes

http://www.karlsims.com/fluid-flow.html

https://www.mikeash.com/thesis/

 

© 2018 sito prototipale studio di GiuseppeGi