Programmazione

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

::cck::76::/cck::
::introtext::

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

::/introtext::
::fulltext::

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/

 

::/fulltext::

Write comment (0 Comments)

::cck::79::/cck::
::introtext::

Tutorial di Programmazione Avanzata in ambiente Linux

In questo Tutorial video si esplora uno studio per combinare un programma scritto in C (che esegue la logica di un qualche algoritmo) con un programma scritto in Java che implementa separatamente una gui per gli input del programma C.

Guarda il VIDEO TUTORIAL COMPLETO

Argomenti trattati nel video tutorial:

  1. Programmazione concorrente in C uso delle funzioni fork() per creare figli del programma corrente
  2. Programmazione avantata in Ambiente Linux, uso di exec() per sovrascrivere un programma in memoria figlio di un programma C con una istanza di un programma .class che mostra una Gui per l'input utente
  3. Sincronizzazione tra padre e figlio mediante la funzione waitpid()
  4. Accesso a File in C 
  5. Creazione di una GUI in Java mediane l'implementazione di una classe che estende JFrame
  6. Gestione degli eventi dei componenti di una gui mediante l'implementazione di un oggetto ActionListener e del relativo metodo actionPerformed
  7. Accesso a File da Java in particolare OutputStrem
::/introtext::
::fulltext::

 

Ciò si realizza tramite un esempio di programmazine concorrente in C nella quale il programma scritto in C si duplica in due programmi concorrenti, il Padre e il Figlio che condividono un file e si sincronizzano su di esso in modo opportuno.

Il pradre si mette in attesa del completamento del Figlio prima di avviare il suo algoritmo.

Il Figlio esegue una classe java e si fa sovrascrivere dall'eseguibile .class nel contesto di menoria, pur restando con il pid creato dal padre, e raccoglie l'input utente inviandolo in un file condiviso con il padre prima di uscire.

Il padre quindi riprende la sua esecuzione leggendo gli input prodotti dal Figlio e li elabora.

Codice Sorgente:

il file C compilare con gcc prog.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
/*
@author Questo indirizzo email è protetto dagli spambots. È necessario abilitare JavaScript per vederlo.
Questo programma crea due processi concorrenti, il padre e un figlio.
Il padre resta in attesa che il figlio raccolga degli input dell utente ed esca, dopodichè
il padre uscito dall'attesa elabora tali input per generare un output.
Il figlio per raccogliere gli input dall'utente si sovrascrive eseguendo una GUI scritta in java
che mostra una interfaccia grafica con caselle di testo e pulsanti dinamicamente create a run time per
consentire all'utente di immettere dei valori, dopodichè salva tali valori in file condiviso con il padre.
Scopo del programma è offrire agli utenti del laboratorio di informatica uno strumento e un tutorial
per integrare GUI scritte in java in algoritmi scritti in C
*/
int main(int argc, char** argv){
    pid_t pid_figlio;
    pid_t pid;
    int status;
    FILE *in;
    
    //creo un figlio
    pid_figlio=fork();
    pid=getpid();
    if(pid_figlio!=0){
        
        printf("[%d] Padre:> attendo l'output del figlio...\n",pid);
        waitpid(pid_figlio, &status, WUNTRACED | WCONTINUED);
        in=fopen("file.dat","r");
        int a,b;
        char str[100];
        fscanf(in,"%d %d %s",&a,&b,&str);
        
        printf("[%d] Padre:> output ricevuto... inizio elaborazione\n",pid);
        printf("Risultato è: %d+%d=%d e la stringa è %s\n",a,b,(a+b),str);
    }else{
        
        in=fopen("input.dat","w");
        fprintf(in,"10 2");
        
        printf("[%d] Figlio:> attendo l'input dell'utente\n",pid);
        //lancio la GUI JAVA con parametri per label e campi
        execlp("java","java","InputForm","Inserisci un valore","Secondo input","Inserisci una stringa",0);
        
    }
    
}


  

 Il file Java. Compilare con javac InputForm.java

/**
@author Questo indirizzo email è protetto dagli spambots. È necessario abilitare JavaScript per vederlo.
Classe che implementa una GUI invocabile anche da un programma C esterno
E' stata realizzata per scopi didattici e di tutorial per gli utenti del laboratorio di informatica
E' utilizzabile invocandola da un programma C per richiedere l'imput all'utente non da riga di comando
ma da una Form con campi di testo e pulsanti definibili dal file C e visualizzabili nella GUI Java.
Può essere usata dal sorgente C creando in esso un processo concorrente (figlio) e sul quale
il programma principale (padre) resta in attesa finche il figlio non ha raccolto tutto l'input
dell'utente tramite la GUI Java.
Quindi con una fork si genera un figlio che sovrascrive il proprio codice con quello della GUI
invocandola con una exec(nomeProgramma,argomenti) in particolare usare la seguente:
execlp("java","java","InputForm","Prima Etichetta Valore","Seconda etichetta","ecc ecc",0);
Il padre quindi resta in attesa mediante una wait(pid_figlio) finché il figlio non ha prodotto
l'output
Padre e Figlio condivideranno il file che questa classe InputForm produrrà alla pressione del tasto
OK

*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class InputForm extends JFrame implements ActionListener{
JPanel pannelloComandi;
JButton okButton;
String output;
JTextField[] textField;

public InputForm(String[] args){
super("Input Form");
this.setSize(640,480);
pannelloComandi=new JPanel();
pannelloComandi.setLayout(new BoxLayout(pannelloComandi,BoxLayout.Y_AXIS));
textField=new JTextField[args.length];
for(int i=0;i<args.length;i++){
JPanel rigo=new JPanel();
rigo.setLayout(new BoxLayout(rigo,BoxLayout.X_AXIS));
rigo.add(new JLabel(args[i]));
textField[i]=new JTextField();
rigo.add(textField[i]);
pannelloComandi.add(rigo);
}
okButton=new JButton("OK, Invia Input e Chiudi Finestra");
okButton.addActionListener(this);
pannelloComandi.add(okButton);
this.add(pannelloComandi);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}

public static void main(String[] args){
InputForm f=new InputForm(args);
}

public void actionPerformed(ActionEvent e){
output="";
for(int i=0;i<textfield.length;i++){
output+=textField[i].getText()+" ";
}
try{
FileOutputStream out=new FileOutputStream("file.dat");
PrintStream s=new PrintStream(out);
s.println(output);
s.close();
out.close();
}catch(IOException ec){
ec.printStackTrace();
}
//System.out.println(output); 
System.exit(1);
}
}
::/fulltext::

Write comment (0 Comments)

Pagina 1 di 3

© 2018 sito prototipale studio di GiuseppeGi