2. sistemi multi-agente

Transcript

2. sistemi multi-agente
UNIVERSITA’ POLITECNICA DELLE
MARCHE
Facoltà di Ingegneria
Corso di laurea in Ingegneria Informatica e
dell’Automazione
SIMULAZIONE MULTI-AGENTE
MEDIANTE LA PIATTAFORMA “MASON”
RELATORE :
Prof. Aldo Franco DRAGONI
Candidato
Mirko BUDANO
Matr. 1024576
Anno Accademico 2008-2009
Indice:
1.
INTRODUZIONE E OBIETTIVI ………………………………..4
2.
SISTEMI MULTI-AGENTE ……………………………………..6
3.
PIATTAFORMA DI SIMULAZIONE MASON ………………..9
3.1. Caratteristiche ………………………………………………...10
3.2. Architettura …………………………………………………...11
3.2.1. Livello “Modello”…………………………………………13
3.2.2. Livello “Visualizzazione”…………………………………14
3.2.3. Livello “Utilità”…………………………………………..17
3.3. Utilizzo di MASON in ECLIPSE ……………………………18
3.3.1. Prerequisiti………………………………………………..18
3.3.2. Installare MASON in ECLIPSE …………………………..19
3.3.3. Creare un nuovo progetto ………………………………...20
3.3.4. Importare un modello MASON …………………………...22
3.3.5. Avviare il modello………………………………………...22
4. IMPLEMENTAZIONE DELLA SIMULAZIONE
MULTI-AGENTE …………………………………………………24
4.1. Descrizione della simulazione ……………………………….24
4.2. Realizzazione del modello …………………………………...30
4.2.1. Model3D.java …………………………………………….30
4.2.2. Orologio.java ……………………………………………..36
4.2.3. Person.java ……………………………………………….37
4.2.4. MovePerson.java …………………………………………40
4.2.5. Variatore Parametri.java ………………………………...42
4.2.6. ViewParametri.java ………………………………………44
4.2.7. Assistente Virtuale.java …………………………………..46
2
4.3. Realizzazione della parte grafica ……………………………47
4.3.1. Model3DWithUI.java …………………………………….47
4.3.2. Altre classi grafiche ………………………………………54
4.4. Librerie Java3D ……………………………………………...56
4.4.1. Scene Graph………………………………………………57
4.4.2. Shape3D…………………………………………………...60
4.4.3. Grouping shapes ………………………………………….62
4.4.4. Luci direzionali……………………………………………63
4.4.5. Classe Loader …………………………………………….65
5. CONCLUSIONI …………………………………………………...67
6. RIFERIMENTI …………………………………………………...68
7. APPENDICE : LIBRERIE DEL MASON ………………………70
8. INDICE DELLE FIGURE ……………………………………….75
3
1. INTRODUZIONE E OBIETTIVI
L’obiettivo di questa tesi è la realizzazione di una simulazione multiagente 3D con l’utilizzo della piattaforma “MASON”.
Mason è l’acronimo di “Multi-Agent Simulator Of Neighborhoods”.
Mason è stato sviluppato alla George Mason University mediante un
progetto di collaborazione tra il “Department of Computer Science’s
Evolutionary Computation Laboratory”
e il “ Center for Social
Complexity”.
La simulazione multi-agente esposta in questa tesi modella un
appartamento in 3D composto da vari ambienti, in cui sono inseriti dei
sensori che rilevano i parametri ambientali. All’interno dell’ambiente
si muove un anziano che ha su di esso dei sensori che rilevano i
parametri vitali e il verificarsi di situazioni particolari come ad
esempio la sua caduta. L’anziano si muove secondo traiettorie
predefinite ed esegue delle azioni durante la giornata.
Inoltre nell’ambiente è stato inserito anche un assistente virtuale che
interagisce con l’anziano e gli fornisce supporto durante la sua attività
quotidiana, ad esempio ricordandogli di prendere le medicine o di
chiudere i rubinetti rimasti aperti.
I parametri ambientali e vitali vengono visualizzati su una finestra
apposita la quale viene aggiornata periodicamente oppure su richiesta
dell’utente premendo il pulsante predisposto a tale scopo.
L’obiettivo di una simulazione è di riprodurre il comportamento di un
sistema reale. In questo contesto, le simulazioni sono perciò un
modello di tali sistemi che consentono all’utente di controllare degli
ambienti per fare sperimentazioni.
4
L’obiettivo della mia simulazione è di monitorare la vita dell’anziano
attuando una forma di ambient assisted living. L’assisted living è
rivolto a quegli anziani che non possono vivere in maniera totalmente
indipendente ma non hanno bisogno di cure mediche 24 ore su 24.
Si introduce quindi il concetto di “casa intelligente” infatti i servizi di
assisted living forniti nella mia simulazione riguardano il supporto
alla vita quotidiana attraverso l’assistente virtuale che interagisce con
l’anziano. Quindi l’assisted living è una filosofia di cure e servizi che
promuove l’indipendenza e la dignità dell’anziano stesso.
Nel seguito della tesi verranno esposte le caratteristiche, l’architettura
e il funzionamento del Mason ed inoltre verrà spiegata in maniera più
approfondita l’implementazione della simulazione sviluppata.
5
2. SISTEMI MULTI-AGENTE
Un sistema multi-agente (MAS) è un sistema composto da più agenti
intelligenti che interagiscono.
Un agente è un’entità virtuale che vive in un ambiente, lo percepisce,
agisce in esso e ha un comportamento autonomo conseguente alla sua
conoscenza, alle sue interazioni e alla sua finalità. Ogni agente
singolarmente valuta la situazione e prende le decisioni sulla base di
una serie di regole.
I sistemi multi-agente possono essere utilizzati per risolvere problemi
che sono difficili o impossibili da risolvere per un singolo agente o per
un sistema monolitico.
Gli agenti hanno importanti caratteristiche:
• Autonomia: gli agenti sono almeno parzialmente autonomi.
• Punto di vista locale: un agente non ha una completa visione del
sistema o il sistema è troppo complesso per un agente per
rendere pratico l’uso di tali conoscenze.
• Decentralizzazione: non c’è nessun controllo agente.
Tipicamente i sistemi multi-agente si riferiscono ad agenti software.
Tuttavia gli agenti potrebbero anche essere robot, umani o gruppi di
umani. Inoltre i sistemi multi-agente possono avere una propria
organizzazione e comportamenti complessi anche quando le strategie
individuali dei singoli agenti sono semplici.
Gli agenti possono condividere le loro conoscenze con una qualsiasi
lingua concordata, entro i limiti del protocollo di comunicazione
utilizzato. Un esempio è il linguaggio di comunicazione della FIPA
(ACL).
6
Molti sistemi multi-agente sono implementati nei computer tramite
delle simulazioni attraverso l’utilizzo di un sistema basato sul time
step, un esempio di questo è la piattaforma Mason come vedremo nel
corso di questa tesi.
Un altro paradigma comunemente utilizzato nei sistemi MAS è il
“feromone”, dove ogni componente fornisce le informazioni agli altri
componenti nelle vicinanze. Questi feromoni potrebbero evaporare
cioè il loro valore diminuisce con il passare del tempo.
La caratteristica principale che si ottiene quando si sviluppa un
sistema multi-agente è la flessibilità, dal momento che un MAS può
essere aggiunto, modificato e ristrutturato senza la necessità di
riscrivere in maniera dettagliata l’applicazione.
Lo studio dei sistemi multi-agente riguarda lo sviluppo e l’analisi di
sofisticati problemi di intelligenza artificiale e il controllo delle
architetture per realizzare tali sistemi.
I sistemi multi-agente ad hoc sono spesso creati da zero ma esistono
anche dei framework che hanno attuato delle norme comuni e che
sono molto utili in quanto consentono di risparmiare tempo,
semplificare lo sviluppo e standardizzare i MAS stessi.
I toolkit per i sistemi multi-agente hanno l’obiettivo di evitare che il
progettista debba partire ogni volta da zero. In particolare evitare che
il progettista debba sviluppare le parti generali di un MAS generico.
Toolkit diversi hanno esigenze o preferenze progettuali diverse.
Esistono 2 tipologie di modelli:
Modelli “forti”: il toolkit ha una definizione rigida di agente e il
progettista deve solo definire i particolari strettamente
dipendenti dall’applicazione.
7
Modelli “deboli”: il toolkit ha una definizione lasca di agente
ed è il progettista a definire le caratteristiche degli agenti. Un
esempio è il Mason che fornisce solo le librerie di base minime
a cui un programmatore java può aggiungere delle funzionalità
specifiche per la sua applicazione.
In generale maggiore è la flessibilità del modello di agente adottato,
minore è la possibilità di un semplice sviluppo grafico del MAS.
La programmazione ad agenti è strettamente basata su quella ad
oggetti in quanto un agente può essere definito in modo naturale come
un oggetto, o meglio come una classe che incapsula le funzionalità
implementate dall’agente i cui metodi e proprietà pubblici definiscono
i servizi che esso mette a disposizione degli altri agenti. Si può usare
un qualunque linguaggio ad oggetti ma la natura distribuita di
un’applicazione multi-agente e l’eterogeneità a livello hardware e di
sistema operativo che si può incontrare in una rete di computer fanno
preferire il linguaggio che per definizione è nato per programmare in
ambienti con tali caratteristiche: Java.
I sistemi MAS sono utilizzati nel mondo reale per applicazioni
grafiche come i giochi per computer. Inoltre sono utilizzati anche nei
film, per il coordinamento dei sistemi di difesa, trasporto, logistica e
in molti altri campi.
8
3. PIATTAFORMA DI SIMULAZIONE MASON
Mason è un toolkit di simulazione single-process e discrete-event
scritto in Java e disegnato con un alto livello di modularità e
flessibilità per essere applicato ad una vasta gamma di simulazioni
multi-agente. Il sistema di simulazione è open-source e gratuito.
Mason non deriva da altri toolkit ma si basa su principi primi.
La filosofia progettuale che sta alla base del Mason è quella di
costruire delle librerie minime, veloci e ortogonali a cui un
programmatore java esperto può facilmente aggiungere delle nuove
funzioni specifiche per un determinato dominio di applicazione. Per
questo è stata aggiunta la visualizzazione grafica e altre facilitazioni
utili per diverse simulazioni.
Le librerie sono destinate ai ricercatori che spesso eseguono
simulazioni con un gran numero di agenti e interazioni ed è per questo
che Mason è veloce, portatile, in grado di garantire risultati replicabili
indipendentemente dalla piattaforma utilizzata.
Il modello Mason può essere fornito di un interfaccia grafica che ne
permette la visualizzazione sia in 2D che in 3D.
Attualmente però Mason non fornisce strumenti di alto livello per
programmatori inesperti né funzioni specifiche che quindi devono
essere aggiunte dal programmatore in base alle sue esigenze. Mason
ha un architettura e delle caratteristiche inusuali per un sistema di
simulazione multi-agente.
Il dominio di applicazione comprende la robotica , intelligenza
artificiale, le scienze sociali e altre scienze.
9
3.1 Caratteristiche
Mason è stato realizzato per avere un sistema di simulazione semplice
e utilizzabile per simulare una vasta gamma di modelli multi-agente.
Le caratteristiche del Mason sono le seguenti:
Basato sul Java.
Ha un piccolo core ed è veloce (soprattutto quando viene
eseguito senza visualizzazione).
Alto livello di modularità e flessibilità.
Il modello è indipendente dalla visualizzazione che può essere
aggiunta, rimossa o modificata in ogni momento.
I modelli possono essere “checkpointed”, recuperati e
trasportati dinamicamente su altre piattaforme con o senza
visualizzazione.
Portatile e produce risultati identici indipendentemente dalla
piattaforma utilizzata.
Le visualizzazioni sono in 2D e 3D.
Supporto efficiente per moltissimi agenti.
Le librerie Mason possono essere facilmente incluse in altre
librerie.
Ci sono tre obiettivi progettuali che non sono stati utilizzati
esplicitamente per realizzare Mason.
In primo luogo Mason non viene utilizzato per effettuare singole
simulazioni in rete su più processori.
In secondo luogo Mason è stato realizzato con un core semplice e
piccolo quindi non ha fornito funzioni speciali per agenti sociali e
simulatori di robotica.
10
In terzo luogo anche se Mason è stato progettato per avere un uso
ragionevolmente efficiente della memoria, essa non rappresenta una
priorità.
3.2 Architettura
Mason è scritto in Java per trarre vantaggio dalla sua portabilità, dalle
definizioni di tipo rigide (che garantiscono la replicabilità dei risultati)
e dalla serializzazione degli oggetti (per salvare e caricare la
simulazione).
Il toolkit Mason è scritto in maniera modulare con un architettura
stratificata come mostrata in figura 3.1.
Figura 3.1 ( Architettura Mason )
Le Utilities sono delle strutture di utilità che possono essere utilizzate
per qualsiasi scopo.
11
Il Simulation Model è una collezione di classi che consiste di uno
schedule a eventi discreti (rappresenta il tempo) , un generatore di
numeri casuali altamente efficiente e una serie di field (campi) che
rappresentano lo spazio. Questo codice da solo è sufficiente per
scrivere delle simulazioni di base avviabili da linea di comando.
Il Visualization e GUI Tools invece permette la visualizzazione dei
field del modello e il controllo da parte dell’utente della simulazione.
Il livello modello e il livello visualizzazione sono perfettamente
separati tra di loro infatti a runtime agisce una suite di strumenti che
consente di prelevare e manipolare il modello mantenendolo
indipendente dalla visualizzazione.
Questo ci consente di trattare il modello come un’entità “selfcontained”. Noi in ogni momento possiamo separare il modello dalla
visualizzazione , fare un checkpoint del modello su disco, passare ad
un'altra piattaforma e riprendere la simulazione da dove era stata
interrotta ottenendo esattamente gli stessi risultati.
La figura 3.2 mostra questa procedura.
Figura 3.2 ( procedura del checkpointing)
12
3.2.1 Livello “Modello”
Il modello Mason è interamente contenuto in una sottoclasse di
SimState. SimState è la superclasse astratta per realizzare il modello
Mason. Il modello può essere completamente indipendente dalla
visualizzazione grafica. Il livello modello consiste di due parti: fields
e discrete-event schedule.
I fields memorizzano degli oggetti arbitrari e li allocano nella loro
posizione spaziale. Gli oggetti sono liberi di appartenere a più fields.
L’uso dei fields è facoltativo e il programmatore può decidere di
aggiungerne degli altri, specifici per le sue esigenze.
Mason fornisce diversi tipi di field:
Array di oggetti 2D o 3D, int o double , delimitati o toroidali e
con un layout esagonale, triangolare o quadrato.
Reti sparse in 2D o 3D, delimitate o toroidali con un layout
esagonale, triangolare o quadrato.
Spazi continui in 2D o 3D.
Spazi discreti in 2D o 3D.
Grafici.
Lo schedule invece rappresenta il tempo e permette agli agenti di
eseguire le loro azioni nel futuro.
Nel Mason il termine agente indica un’entità computazionale che può
essere programmata per eseguire delle azioni e che può manipolare
l’ambiente. Questo però non implica che l’agente sia fisicamente
contenuto nell’ambiente stesso.
Mason non programma gli eventi da inviare ad un agente ma è
l’agente stesso che programma le sue attività. La pianificazione di
13
un’agente per eseguire diverse funzioni può essere facilmente
effettuata con una apposita classe.
Una simulazione di base tipicamente consiste di uno o piu fields, uno
schedule e degli oggetti ausiliari definiti dall’utente.
Il modello è self-contained quindi può essere salvato su disco, caricato
su un'altra piattaforma ed eseguito con gli stessi risultati. Inoltre il
modello non contiene nessuna visualizzazione e può essere lanciato
anche senza.
3.2.2 Livello “Visualizzazione”
La simulazione Mason può operare con o senza un’interfaccia grafica
(GUI) e può commutare tra due modelli durante la simulazione stessa.
Per
fare
ciò
il
modello
è
completamente
separato
dalla
visualizzazione. Quando opera senza visualizzazione il modello viene
eseguito come una normale applicazione java. Invece quando opera
con visualizzazione il modello è mantenuto nella propria “sandbox”
(buca nella sabbia) ed è eseguito per conto proprio senza che la GUI
possa modificare le informazioni del modello.
Gli oggetti del livello visualizzazione possono esaminare gli oggetti
del livello modello solo con il permesso di un gatekeeper wrapper
chiamato GUIState. Questa classe consente di staccare il modello
dalla visualizzazione.
Dato che alcuni oggetti della visualizzazione hanno bisogno di essere
programmati (in particolare le finestre che devono essere aggiornate
per riflettere i cambiamenti del modello) allora la GUIState fornisce
un proprio mini-schedule ausiliario tenuto in sintonia con lo schedule
del modello.
14
Lo schedule del modello e quello ausiliario sono separati attraverso un
controller che ha il compito di far partire la simulazione grafica.
Mason realizza la visualizzazione attraverso uno o più display ovvero
delle finestre grafiche che forniscono una vista in 2D o 3D dei field
del modello. I displays hanno molte relazioni con i fields, inoltre i
display3D possono visualizzare anche fields 2D.
La GUI non visualizza e manipola il modello direttamente ma
attraverso dei “fields portrayals” (ritratti) che agiscono come delegati
per gli oggetti e i fields del modello.
I fields portrayal rappresentano graficamente i fields del modello
chiamando dei simple portrayal che sono responsabili del disegno e
del controllo degli oggetti memorizzati nei fields.
Gli oggetti possono anche fornire un proprio simple portrayal
specifico che esegue il disegno per quel tipo di oggetto.
Ci sono vari tipi di fields portrayals che sono, a turno, attaccati ad un
display e provvedono a disegnare e manipolare l’ambiente grafico
sulla base dei loro fields object deleganti.
Mason inoltre fornisce anche una console che facilità l’utente nelle
operazioni di start/pause/stop della simulazione ed inoltre consente di
salvare e caricare i modelli serializzati, mostrare e nascondere i
displays e visualizzare gli ispettori.
Mason realizza la visualizzazione sia in 2D ( usando AWT e java2D)
che in 3D (usando le librerie Java3D).
La figura 3.3 mostra schematicamente i componenti del Mason e le
relazioni che intercorrono tra di essi.
15
Figura 3.3 ( Componenti del Mason)
16
3.2.3 Livello “Utilità”
Il livello Utilità contiene delle classi che possono essere utilizzate per
qualsiasi scopo.
Ad esempio le classi di utilità comprendono delle “bag”, vettori
immutabili in 2D o 3D , un’implementazione molto efficiente di un
generatore di numeri casuali e tante altre classi utili.
Le “bag” sono dei contenitori che hanno la stessa struttura degli
arraylist ma sono molto più veloci. Le bag forniscono dei metodi per
aggiungere o rimuovere degli elementi, per scorrere tutti gli elementi
contenuti in essa e per accedere direttamente ad ogni elemento tramite
un indice.
17
3.3 Utilizzo di Mason in Eclipse
Per sviluppare la mia simulazione multi-agente ho utilizzato come
ambiente di programmazione Eclipse. Eclipse è un ambiente di
sviluppo integrato potente e largamente utilizzato ed è una piattaforma
conveniente per sviluppare il modello Mason.
Eclipse è gratis, disponibile per windows, linux e per mac, fornisce un
editor per scrivere programmi java, display grafici del programma,
una gerarchia dei package ed anche un debugger.
Usare Eclipse è conveniente in quanto fornisce degli aiuti durante la
scrittura del codice e nel caso di errori sintattici indica i modi possibili
per risolverli.
3.3.1 Prerequisiti
Per poter utilizzare la piattaforma Mason è necessario eseguire dei
passi preliminari.
Innanzitutto
bisogna
scaricare
dal
sito
http://www.cs.gmu.edu/~eclab/projects/mason/
il
della
Mason
programma
in
formato compresso e decomprimerlo.
Una volta decompresso si ottiene una cartella che contiene le librerie
necessarie per eseguire le simulazioni.
Il passo successivo è scaricare delle librerie opzionali ovvero
JFreeChart,
iText e Java Media Framework. Per l’installazione
seguire le indicazioni contenute nel file readme.
Per eseguire simulazioni 3D è necessario installare il Java3D
framework dal sito della Sun e copiare i file .jar nella cartella del
Mason.
18
Dopo aver eseguito queste operazioni la fase successiva è configurare
Eclipse per l’utilizzo del Mason.
3.3.2 Installare Mason in Eclipse
Per installare Mason in Eclipse bisogna seguire i seguenti passi:
Lanciare Eclipse, appena viene eseguito chiederà la directory da
utilizzare come workspace.
Dopo aver lanciato Eclipse bisogna creare un progetto che
contiene il MASON.
• Selezionare
File New Project. Selezionare Java
Project e cliccare su Next.
• Nella finestra che compare indicare come nome del progetto
“MASON” , cliccare su Create new project in workspace, e
Create separate source and output folders. Poi cliccare su
Finish per chiudere la finestra.
• Espandere il progetto MASON cliccando sul + alla sua
sinistra, cliccare con il tasto destro del mouse su “src” e
selezionare Import File system Next. Selezionare la
cartella MASON ,cliccare su OK e selezionare le caselle
corrispondenti a ec e sim come mostrato nella figura 3.4.
19
Figura 3.4 (Installazione Mason in Eclipse)
3.3.3 Creare un nuovo progetto
Questo passo viene eseguito se si vuole creare un modello Mason
dall’inizio.
Le operazioni da eseguire sono:
Selezionare
File New Project. Poi selezionare Java
Project e cliccare su Next.
Nella nuova finestra indicare il nome del progetto e selezionare
Create separate source and output folders. Cliccare su Next
per visualizzare la finestra con i Java settings.
20
Cliccare su Projects e selezionare Add. Cliccare sulla casella
che indica il progetto MASON creato precedentemente e
premere il tasto Finish come indicato nella figura 3.5.
Figura 3.5 (Creazione di un nuovo progetto)
Creare un nuovo package in cui inserire le classi che verranno
create. A questo punto siamo in grado di iniziare a scrivere il
nostro modello di simulazione MASON.
21
3.3.4 Importare un modello Mason
Questo passo viene eseguito se si vuole importare un modello
Mason già esistente.
Le operazioni da eseguire sono le seguenti :
Selezionare
File New Project. Poi selezionare Java
Project e cliccare su Next.
Nella nuova finestra indicare il nome del progetto e selezionare
Create separate source and output folders. Cliccare su Next
per visualizzare la finestra con i Java settings.
Cliccare su Projects e selezionare Add. Cliccare sulla casella
che indica il progetto MASON creato precedentemente e
premere il tasto Finish.
Creare un nuovo package. Cliccare con il tasto destro del mouse
sul package e selezionare Import File system. Nella finestra
che compare selezionare la cartella che contiene il modello da
importare e indicare i file da importare.
A questo punto il modello è stato importato e la simulazione
può essere avviata.
3.3.5 Avviare il modello
Per eseguire il modello bisogna seguire i seguenti passi:
Selezionare Run Run. Nella finestra che si apre selezionare
“Run configuration”. A questo punto selezionare Java
Application , cliccare su New e indicare il nome del package e
il nome della classe che contiene il metodo main. Poi cliccare
su Run come indicato nella figura 3.6.
22
Figura 3.6. (Avviare un progetto)
Una volta configurato è possibile riavviare il programma
cliccando su Run Run Last Launched on nel menù Eclipse.
23
4. IMPLEMENTAZIONE DELLA SIMULAZIONE
MULTI-AGENTE
4.1 Descrizione della simulazione
La simulazione multi-agente esposta in questa tesi modella un
appartamento in 3D composto da varie stanze.
All’interno dell’ambiente si muove un anziano il quale ha dei sensori
che rilevano i parametri vitali e il verificarsi di situazioni particolari
come ad esempio la sua caduta.
In ogni ambiente è presente un sensore che rileva i parametri
ambientali ed un assistente virtuale che interagisce con l’anziano e gli
fornisce supporto durante la sua attività quotidiana, ad esempio
ricordandogli di prendere le medicine o di chiudere i rubinetti rimasti
aperti. Nella figura 4.1. è rappresentato il sensore ambientale e
l’assistente virtuale.
Figura 4.1 (Assistente virtuale e sensore)
I parametri ambientali e vitali vengono visualizzati su una finestra
apposita la quale viene aggiornata periodicamente oppure su richiesta
dell’utente premendo il pulsante predisposto a tale scopo.
24
L’obiettivo della simulazione è monitorare la vita dell’anziano tramite
i sensori per eventualmente intervenire in caso di necessità.
La figura 4.1 mostra una panoramica dell’appartamento in cui vive
l’anziano. Come si nota dalla figura sottostante l’appartamento è
composto da una cucina, da una camera da letto, da un bagno e da un
salotto.
Figura 4.2 (Panoramica della casa)
L’anziano si muove secondo delle traiettorie predefinite ed esegue
delle azioni nell’arco della giornata.
La giornata dell’anziano inizia alle 8:00 recandosi in cucina per fare
colazione. Una panoramica della cucina è mostrata in figura 4.3.
Dopo la colazione alle 8:30 l’anziano si avvia verso il bagno per
svolgere i suoi bisogni fisiologici. Durante il percorso l’anziano cade
e l’assistente virtuale gli chiede se ha bisogno di aiuto. Una
panoramica del bagno è mostrata in figura 4.4.
25
Figura 4.3 (Panoramica della cucina)
Figura 4.4 (Panoramica del bagno)
Dopo essere andato in bagno l’anziano si reca in camera per leggersi
un libro. La panoramica della camera è mostrata in figura 4.5.
Dopo una fase di lettura l’anziano va in salotto a guardare la tv.
Una panoramica del salotto è mostrata in figura 4.6.
26
Figura 4.5 (Panoramica della camera)
Figura 4.6 (Panoramica del salotto)
27
Alle ore 10:00 il figlio fa visita all’anziano e per passare il tempo
giocano a scacchi. Una panoramica della partita a scacchi e mostrata
in figura 4.7.
Alle ore 11:00 il figlio lascia la casa e l’anziano torna a sedersi sul
divano a guardare la tv.
Alle ore 12:00 l’anziano si reca in cucina e si mette a cucinare,
terminata la preparazione si mette a tavola e subito dopo lava i piatti.
Dopo aver eseguito queste azioni l’anziano torna in salotto e si sdraia
sul divano per riposarsi. Il riposo va avanti finchè l’anziano non sente
nuovamente un bisogno fisico, quindi si reca in bagno. Durante il
tragitto l’anziano cade e l’assistente virtuale gli chiede se ha bisogno
di aiuto. Dopo essere andato in bagno torna sul divano a guardare la
tv. Alle ore 17:00 l’assistente virtuale gli ricorda di prendersi le
medicine quindi l’anziano si alza, provvede a prendere le medicine e
poi torna a sedere sul divano.
Alle ore 18:00 squilla il telefono e l’assistente virtuale lo informa che
c’è il figlio in linea, quindi l’anziano risponde.
Alle ore 19:00 l’assistente virtuale fa una panoramica dei parametri
vitali dell’anziano.
Alle ore 20:00 l’anziano inizia a prepararsi la cena, terminata la
preparazione si mette a tavola e dopo la cena lava i piatti. Dopo aver
lavato i piatti torna sul divano a guardare la tv.
Resta a guardare la tv fino alle 23:00 , poi va in camera, chiude le
finestra e si mette a dormire fino alla mattina.
28
Figura 4.7 (Anziano con il figlio)
29
4.2 Realizzazione del modello
Il modello è interamente contenuto in una sottoclasse di SimState.
SimState è la superclasse astratta per la realizzazione del modello
Mason. Il livello modello consiste di due parti: fields e discrete-event
schedule.
I fields memorizzano degli oggetti arbitrari e li allocano nella loro
posizione spaziale.
Lo schedule invece rappresenta il tempo e permette agli agenti di
eseguire le loro azioni nel futuro.
Mason non programma gli eventi da inviare ad un agente ma è
l’agente stesso che programma le sue attività. La pianificazione di
un’agente per eseguire le diverse funzioni può essere facilmente
effettuata con una apposita classe che estende Steppable.
Una simulazione di base tipicamente consiste di uno o piu fields, uno
schedule e degli oggetti ausiliari definiti dall’utente.
La classe principale che ho utilizzato per la creazione del modello è
Model3D.java. Le altre classi necessarie per la realizzazione della
simulazione
sono
MovePerson.java,
la
classe
Orologio.java,
VariatoreParametri.java
,
Person.java,
ViewParametri
e
AssistenteVituale.java.
Nel seguito verrà esposta la struttura e le funzioni di ognuna delle
classi sopra citate.
4.2.1 Model3D.java
Model3D.java è una sottoclasse di sim.engine.SimState che è la classe
di base per modellare una simulazione Mason.
30
SimState ha 2 variabili fondamentali:
• random: è un generatore di numeri casuali che utilizza
l’algoritmo ec.util.MersenneTwisterFast. Tale algoritmo è
molto efficiente in quanto utilizza una matrice di ricorrenza
lineare su campo binario.
• Sim.engine.schedule: è la rappresentazione del tempo. Consente
agli agenti di eseguire le loro azioni nel futuro.
Il codice della classe Model3D.java è il seguente:
import sim.engine.*;
import sim.util.*;
public class Model3D extends SimState
{
static final long serialVersionUID=1;
double width = 60;
double height = 60;
double length = 60;
public House house;
Person p;
public Model3D(long seed){
super(seed);
}
public void start(){
super.start();
house = new House(this,width,height,length);
house.setHouse();
//creo orologio che simula lo scorrimento del tempo
Orologio orologio=new Orologio(1);
house.setObjectLocation(orologio,
new Double3D(0,15,-55));
schedule.scheduleRepeating(0,0,orologio,1);
//creo la persona che si muove nell'ambiente
p=new Person(orologio);
31
house.setObjectLocation(p,new Double3D(50,Y,-30));
schedule.scheduleRepeating(Schedule.EPOCH,1,p,1);
//creo ospite
Ospite ospite=new Ospite(orologio);
schedule.scheduleRepeating(Schedule.EPOCH,
1,ospite);
//creo i vari sensori ambientali
SensoriAmbientali sensAmb1=new SensoriAmbientali(house)
house.setObjectLocation(sensAmb1,new Double3D(-30,8,50.6));
…
//creo il sensore vitale posizionato addosso alla persona
SensoriVitali sensVitali=new SensoriVitali(p);
//creo il sensore per il gas
SensoreGas sGas=new SensoreGas(this);
//creo un agente che fa variare tutti i parametri
adeguatamente nell'arco della giornata
VariatoreParametri var= new VariatoreParametri(
this,orologio,house,p);
schedule.scheduleRepeating(Schedule.EPOCH,1,var,1);
//creo un coordinatore che mi interroga i sensori e mi
fornisce i valori delle misurazioni
ViewParametri vP=new ViewParametri(orologio,sensAmb1,
sensVitali, sGas);
schedule.scheduleRepeating(0,1,vP,1);
}
public static void main(String[] args){
doLoop(Model3D.class, args);
System.exit(0);
}
}
Il costruttore di Model3D.java prende come parametro un numero
casuale che dipende dall’orologio interno del sistema.
Il metodo start ( ) viene chiamato quando inizia la simulazione e si
occupa di :
Creare il field.
32
Inizializzare il field per creare i componenti dell’ambiente
domestico.
Creare l’orologio e sincronizzarlo con lo schedule del modello
Mason.
Creare l’anziano, collocarlo nella posizione iniziale e avviare il
suo comportamento che è predefinito e dipende dal valore
dell’orologio.
Creare i sensori ambientali e collocarli all’interno della casa.
Creare i sensori vitali.
Creare la classe VariatoreParametri che fa variare i parametri
vitali e ambientali in modo casuale per ottenere un andamento
realistico.
Creare la classe ViewParametri che visualizza periodicamente
in una finestra sia i parametri vitali che quelli ambientali.
Il field che ho utilizzato per rappresentare lo spazio è la classe
House.java che estende la classe Continuous3D.
La struttura della classe House è la seguente:
import sim.field.continuous.Continuous3D;
import sim.util.Double3D;
public class House extends Continuous3D
{
//costruttore
public House(Model3D model,double w, double h, double l){
super(1,w,h,l);
this.model=model;
}
//metodo che mi imposta i componenti dentro casa
public void setHouse(){
…
33
…
}
}
Sim.field.continuous.Continuous3D rappresenta uno spazio continuo
tridimensionale.
Il costruttore ha 4 parametri:
Livello di discretizzazione : deve essere più grande della
dimensione massima di ogni oggetto che si prevede di mettere
in Continuous3D per essere sicuri che la ricerca degli oggetti
sia efficiente all’interno dello spazio 3D.
Larghezza
Altezza
Lunghezza
Inoltre tale classe prevede diversi metodi. Quelli che ho usato nella
mia simulazione sono:
setObjectLocation (Object obj, Double3D location): si occupa
di collocare l’oggetto obj nella posizione location.
getObjectLocation (Object obj): ritorna la posizione attuale
dell’oggetto obj.
getObjectsWithinDistance(Double3D position,Double distance)
ritorna una bag che contiene tutti gli oggetti che si trovano
entro la distanza distance rispetto al punto position.
Sim.engine.schedule invece rappresenta il tempo e consente agli
agenti di eseguire delle azioni nel futuro.
Si possono pianificare eventi che si verificano una sola volta oppure
più volte in un intervallo di tempo. In questo caso lo schedule fornisce
34
un oggetto di tipo Stoppable su cui è possibile chiamare il metodo
stop( ) che consente di cancellare tutte le ripetizioni future dell’evento.
Lo schedule è di tipo discrete-event cioè il tempo è discreto ed è
composto da time step. Ad ogni time step lo schedule chiama tutti gli
eventi in programma in quel momento. Possono essere programmati
anche eventi multipli nello stesso tempo. Gli eventi programmati per
lo stesso momento sono classificati in base al loro ordering definito
da un numero intero. Gli agenti che hanno un ordinamento più basso
vengono eseguiti prima degli altri.
Se gli agenti previsti per lo stesso tempo hanno anche lo stesso
ordinamento allora la loro esecuzione è determinata in maniera
casuale. È possibile ottenere il numero di volte che il metodo step ( ) è
stato chiamato utilizzando il metodo getStep( ) .
Lo schedule fornisce diversi metodi ma il metodo principale che ho
utilizzato nella mia simulazione è schedule.scheduleRepeating (
double time, int ordering, Steppable agent, double interval).
Questo metodo consente all’agente di eseguire le sue azioni a partire
dall’istante di tempo definito da time con un ordinamento pari a
ordering. Il valore di interval invece definisce la frequenza di
esecuzione delle azioni, ad esempio se vale 1 significa che agent
esegue le sue azioni ogni time step .
Il valore normalmente utilizzato per time è Schedule.EPOCH che
rappresenta il primo tempo utile per la schedulazione.
Nella piattaforma Mason un agente è un oggetto che implementa
l’interfaccia Steppable. Tale interfaccia prevede un solo metodo
ovvero step( ) che definisce il comportamento dell’agente nel corso
del tempo. Tale metodo viene chiamato automaticamente dallo
schedule.
35
Nel modello inoltre vengono creati anche i sensori vitali e i sensori
ambientali. La loro funzione è quella di fornire i valori delle
rilevazioni effettuate nel momento in cui vengono interrogati.
I parametri vitali sono contenuti nella classe Person.java mentre i
parametri ambientali sono contenuti nella classe House.java . Tali
parametri vengono fatti variare dalla classe VariatoreParametri.java
e vengono visualizzati tramite la classe ViewParametri.java. Queste
classi saranno esposte in maniera più approfondita nel seguito.
4.2.2 Orologio.java
La classe Orologio.java è un agente che implementa l’interfaccia
Steppable. Il metodo step( ) viene eseguito ad ogni time step e
consente all’orologio di rimanere sincronizzato con lo schedule del
modello Mason. Ogni time step l’orologio viene incrementato di un
secondo. Quando il valore di steps raggiunge circa il valore 86000
significa che la giornata è finita e quindi la simulazione viene
interrotta.
L’orologio è un componente fondamentale del modello perché
sincronizza le varie classi .
Il codice di tale classe è il seguente:
import sim.engine.*;
import sim.portrayal.DrawInfo2D;
import sim.portrayal3d.SimplePortrayal3D;
public class Orologio extends SimplePortrayal3D implements
Steppable
{
public int ore=8;
public int minuti;
public int secondi;
public int steps;
public int n;
36
public Orologio(int n){
this.n=n;
}
public void step(SimState state){
steps++;
secondi++;
if(secondi==60){
minuti++;
secondi=0;
if(minuti==60){
ore++;
minuti=0;
if(ore==24){
ore=0;
}
}
}
if(steps==86000){
((Model3D)state).schedule.reset();
((Model3D)state).finish();
}
}
//metodo che mi disegna l'orologio
public TransformGroup getModel(Object obj, TransformGroup
j3dModel)
{
…
}
}
4.2.3 Person.java
La classe Person.java è un agente che implementa l’interfaccia
Steppable. Il metodo principale di tale classe è step( ) che consente
all’agente ovvero all’anziano di eseguire delle azioni nel corso della
giornata in base al tempo che scorre. Le azioni eseguite dipendono dal
37
valore corrente dell’orologio che è sincronizzato con lo schedule del
modello Mason.
La classe Person.java estende anche la classe SimplePortrayal3D che
consente di disegnare l’anziano utilizzando le funzionalità del Java3D
come vedremo nel seguito di questa tesi.
La classe Person.java tra le classi della simulazione è quella più lunga
in quanto definisce tutti i comportamenti dell’anziano nell’arco della
giornata.
Il codice di tale classe è:
import sim.engine.*;
import sim.util.*;
import sim.portrayal3d.SimplePortrayal3D;
public class Person extends SimplePortrayal3D implements Steppable
{
static final long serialVersionUID=1;
public static final int move=0;
public static final int sit=1;
public static final int disteso=2;
public static final int caduto=3;
//variabili istanza
…
…
//metodo step
public void step(SimState state){
model=(Model3D)state;
this.loc=model.house.getObjectLocation(this);
//alle 8
si alza e va in cucina
if((orologio.ore==8)&&(orologio.minuti==0)&&(
orologio.secondi==0||orologio.secondi==1))
{
Double3D[] newLoc ={new Double3D(40,model.Y,-20),
new Double3D(43,model.Y,0),
new Double3D(43,model.Y,38),
new Double3D(38,model.Y+1,38),
null};
comp=move;
finalComp=sit;
38
mp=new MovePerson(this);
mp.setMovement(newLoc,finalComp);
s=model.schedule.scheduleRepeating(orologio.n*
orologio.steps,mp,1);
}
//alle 8:30 si alza dal tavolo e cade
if((orologio.ore==8)&&(orologio.minuti==30)&&
(orologio.secondi==0)){
Double3D[] newLoc ={new Double3D(43,model.Y,0),
new Double3D(43,model.Y,-9),
new Double3D(43,model.Y-3.5,-10),
null};
comp=move;
finalComp=caduto;
mp.setMovement(newLoc,finalComp);
s=model.schedule.scheduleRepeating(orologio.n*
orologio.steps,mp,1);
}
//esegue le altre azioni della giornata
…
…
}
//metodo che mi disegna omino
public TransformGroup getModel(Object obj, TransformGroup
j3dModel){
…
}
//metodo che mi imposta la rotazione dell'omino
public Transform3D setTransform(){
…
}
//metodo che mi aggiunge dei componenti aggiuntivi in base al
tempo che scorre
public TransformGroup setComponent(){
…
}
39
In base al valore dell’orologio l’anziano esegue delle azioni quindi il
metodo step( ) è una sequenza di if come mostrato in breve dal codice
sovrastante.
Gli altri metodi della classe sono :
getModel(Object obj, TransformGroup j3dModel) : viene
eseguito ogni time step per caricare il disegno dell’anziano
in base all’azione che sta svolgendo.
setTransform( ): viene utilizzato per eseguire la rotazione
dell’anziano durante il suo movimento in base alla traiettoria
seguita.
setComponent( ): aggiunge dei componenti aggiuntivi alla
scena grafica in base al valore dell’orologio.
Nel metodo step( ) vengono definite le traiettorie che l’anziano segue
nel corso della giornata. Il movimento vero e proprio viene eseguito
dalla classe MovePerson.java che varrà esposta in seguito.
4.2.4 MovePerson.java
La classe MovePerson.java consente all’anziano di muoversi da un
punto all’altro della casa.
Il codice di tale classe è il seguente:
import sim.util.*;
import sim.engine.*;
public class MovePerson implements Steppable
{
//variabili istanza
…
…
//costruttore
public MovePerson(Person p){
this.p=p;
}
40
//imposta le caratteristiche del movimento da eseguire
public void setMovement(Double3D[] newLoc,int c){
…
}
//metodo step
public void step(SimState state){
Model3D model=(Model3D)state;
if(newLoc[i]!=null){
moveTo();
double newx=loc.x+xdir;
double newz=loc.z+zdir;
loc=new Double3D(newx,newLoc[i].y,newz);
model.house.setObjectLocation(p,loc);
if(Math.abs(loc.x-newLoc[i].x)<0.3
&&Math.abs(loc.z-newLoc[i].z)<0.3) {
model.house.setObjectLocation(p,newLoc[i]);
i++;
}
}
if(i==n) {
p.setComportamento(comp);
p.s.stop();
}
}
//metodo che in base ai punti da raggiungere effettua lo
spostamento
public void moveTo(){
…
}
}
Il costruttore prende come argomento un oggetto di tipo Person in
modo da collogarsi con l’anziano.
Il metodo setMovement(Double3D [ ] newLoc, int c) imposta il
movimento da eseguire infatti ha 2 parametri:
Double3D [ ] newLoc : è un vettore di punti 3D che definisce la
traiettoria seguita dall’anziano.
41
int c : è un intero che definisce il comportamento dell’anziano
quando raggiunge il punto finale di newLoc . Può assumere
diversi valori a seconda che l’anziano stia in piedi , seduto,
disteso oppure caduto per terra.
Il metodo step( ) consente all’anziano di eseguire dei piccoli
movimenti per raggiungere il prossimo punto previsto dal vettore
della traiettoria. Una volta che l’anziano ha raggiunto il punto finale il
movimento viene interrotto dal metodo p.s.stop( ) e viene impostato il
suo comportamento finale che può essere in piedi , seduto, caduto o
disteso.
Il metodo moveTo( ) determina le direzioni del movimento in base al
prossimo punto da raggiungere.
4.2.5 VariatoreParametri.java
La classe VariatoreParametri.java si occupa di far variare i parametri
vitali e ambientali nell’arco della giornata nel modo più realistico
possibile. I parametri da far variare sono :
Temperatura dell’ambiente
Umidità
Luminosità
Temperatura corporea
Pressione arteriosa
Frequenza cardiaca
Il codice della classe è :
import sim.engine.SimState;
import sim.engine.Steppable;
public class VariatoreParametri implements Steppable
{
//variabili istanza
…
42
//costruttore
public VariatoreParametri(Model3D m,Orologio clock,House
house,Person p){
this.model=m;
this.orologio=clock;
this.house=house;
this.p=p;
}
//metodo step
public void step(SimState state)
{
double x;
//variazione temperatura ambientale
if(orologio.ore<15){
if((orologio.minuti==0 ||
orologio.minuti==30)&&(orologio.secondi==0)){
x=house.getTemperatura()+0.2+(model.random.
nextDouble()*0.2-0.1);
house.setTemperatura(x);
}
}
else {
if((orologio.minuti==0 ||
orologio.minuti==30)&&(orologio.secondi==0)){
x=house.getTemperatura()+0.2+(model.random.
nextDouble()*0.2-0.1);
house.setTemperatura(x);
}
}
//variazione umidità
…
//variazione luminosità
…
//variazione temperatura corporea
…
//variazione pressione
…
//variazione frequenza cardiaca
…
}
43
Il metodo step( ) si occupa di far variare i parametri a intervalli di
tempo regolari. Ho scelto di farli variare casualmente ogni mezz’ora.
4.2.6 ViewParametri.java
La classe ViewParametri.java interroga periodicamente i sensori
ambientali e vitali e visualizza i risultati delle rilevazioni su
un’apposita finestra.
Il codice della classe è il seguente:
import java.awt.*;
import javax.swing.*;
import sim.engine.*;
import sim.util.Double3D;
public class ViewParametri implements Steppable , ActionListener
{
//variabili istanza
…
//costruttore che crea la finestra e la posiziona
public ViewParametri(Orologio o, Sensori Ambientali sA,
SensoriVitali sV,SensoreGas sG)
{
…
…
}
//metodo step
public void step(SimState state){
…
}
public void actionPerformed(ActionEvent e){
…
}
}
44
Il costruttore inizializza le variabili di istanza e crea la finestra di
visualizzazione dei parametri.
Il metodo step( ) si occupa di interrogare periodicamente i sensori
vitali e ambientali per aggiornare la finestra.
Il metodo actionPerformed (ActionEvent e) consente di interrogare e
aggiornare la finestra di visualizzazione quando viene premuto
l’apposito pulsante collocato sulla finestra stessa.
La finestra di visualizzazione è mostrata in figura 4.8.
Figura 4.8 ( Finestra di visualizzazione)
45
4.2.7 AssistenteVirtuale.java
La
classe
AssistenteVirtuale.java
si
occupa
di
gestire
la
visualizzazione dell’assistente virtuale e di fornire supporto
all’anziano durante la sua attività quotidiana. L’assistente virtuale si
occupa di:
Fornire un messaggio di buongiorno all’anziano in cui lo
informa che i suoi parametri vitali sono nella norma.
Nel caso della caduta dell’anziano gli chiede se ha bisogno di
aiuto.
Ricordare all’anziano di prendersi le medicine.
Far notare all’anziano eventuali rubinetti rimasti aperti.
Rispondere al telefono e mettere in comunicazione l’anziano
con il chiamante.
Fornire all’anziano un riepilogo dei suoi parametri vitali.
Queste funzioni vengono eseguite tramite una voce sintetizzata
realizzata utilizzando un apposito software adatto allo scopo.
La riproduzione dell’audio viene attuata utilizzando un’apposita classe
Suono.java che carica e riproduce un suono in formato .wav.
46
4.3 Realizzazione della parte grafica
La simulazione Mason può operare con o senza un’interfaccia grafica
(GUI). Per fare ciò il modello è separato dalla visualizzazione. Nella
mia simulazione la visualizzazione grafica è fondamentale.
Gli oggetti del livello visualizzazione possono esaminare gli oggetti
del livello modello solo con il permesso di un gatekeeper wrapper
chiamato GUIState. Questa classe consente di staccare il modello
dalla visualizzazione.
4.3.1 Model3DWithUI.java
La classe principale che ho utilizzato per la gestione grafica della
simulazione è Model3DWithUI.java. Tale classe estende GUIState.
Il codice della classe Model3DWithUI.java è il seguente:
import sim.engine.*;
import sim.display.*;
import sim.display3d.Display3D;
import sim.portrayal3d.continuous.ContinuousPortrayal3D;
import javax.media.j3d.*;
import javax.swing.*;
import javax.vecmath.*;
import com.sun.j3d.loaders.*;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.image.TextureLoader;
public class Model3DWithUI extends GUIState
{
public Display3D display;
public JFrame displayFrame;
ContinuousPortrayal3D housePortrayal=new
ContinuousPortrayal3D();
public static void main(String[] args)
{
Model3DWithUI m=new Model3DWithUI();
Console c=new Console(m);
47
c.setVisible(true);
}
//costruttori
public Model3DWithUI()
{
super(new Model3D(System.currentTimeMillis()));
}
public Model3DWithUI(SimState state)
{
super(state);
}
public static String getName() { return "Prova: Casa"; }
//metodo quit
public void quit()
{
super.quit();
if (displayFrame!=null) displayFrame.dispose();
displayFrame = null;
// let gc
display = null;
// let gc
}
//metodo init che inizializza la simulazione
public void init(Controller c){
super.init(c);
Model3D m=(Model3D)state;
// make the display
display = new Display3D(750,750,this,1);
display.attach(housePortrayal,"house");
float scale =(float)
Math.max(Math.max(m.width,m.height), m.length);
display.scale(1f/scale);
//creo e registro il frame del display3D con la console
displayFrame = display.createFrame();
c.registerFrame(displayFrame);
displayFrame.setVisible(true);
}
public void start()
{
super.start();
48
setupPortrayals();
}
public void load(SimState state)
{
super.load(state);
setupPortrayals();
}
//metodo setupPortrayal
public void setupPortrayals()
{
display.destroySceneGraph();
Model3D m=(Model3D)state;
housePortrayal.setField(m.house);
display.reset();
display.createSceneGraph();
display.root.addChild(createScene());
display.root.addChild(creaPavimento());
}
//carica la scena grafica dal file
public BranchGroup createScene()
{
//Crea la radice del branch graph
BranchGroup objRoot=new BranchGroup();
…
…
return objRoot;
}
public BranchGroup creaPavimento(){
…
}
}
Dopo aver messo il codice relativo alla classe procedo alla
spiegazione di esso.
Sim.Display.GUIState è la superclasse astratta per la costruzione e la
gestione della grafica. Si occupa di controllare il modello e di gestire
un mini-schedule ausiliario associato a quello del modello stesso.
49
Tale classe prevede 2 costruttori, uno prende come parametro una
SimState e l’altro crea la SimState al volo.
Il metodo main crea una Console che ha come parametro un’istanza
della classe GUIState. La Console è un controller che consente
all’utente di manipolare lo schedule e sta alla base della simulazione
grafica. I suoi principali compiti sono:
Riproduzione, arresto e pausa della simulazione.
Visualizzazione del time corrente.
Controllo del generatore di numeri casuali.
Salvataggio e caricamento della simulazione.
Visualizzazione dei display.
Una rappresentazione della console è mostrata in figura 4.9.
Figura 4.9 (Console del mason)
50
Il metodo init (Controller c) viene utilizzato per inizializzare la
simulazione. Tale metodo è chiamato quando la GUI viene avviata per
la prima volta. Si occupa di :
Creare il display3D.
Creare il frame che conterrà il display.
Registrare il frame con la console.
Attaccare il portrayal3D con il display3D.
Sim.display3d.Display3D
visualizza
e
manipola
gli
oggetti
portrayal3D consentendo all’utente di ruotarli, ingrandirli, modificare
le sequenza di aggiornamento, scattare delle fotografie e filmati della
simulazione.
Display3D è Steppable infatti ad ogni time step viene aggiornato e
ridisegnato. Il costruttore prende 4 parametri:
Double width: larghezza della regione.
Double height: altezza della regione.
GUIState simulation: è la simulazione da visualizzare.
Long interval: intervallo di visualizzazione del display.
Il display3D può essere collocato in un JFrame che si ottiene
chiamando l’apposita funzione
display.createFrame( ) fornita dal
display3D stesso. Una volta creato il frame deve essere registrato con
la
console
per
consentirle
di
gestire
la
visualizzazione
e
l’aggiornamento all’interno del frame stesso. La registrazione viene
effettuata utilizzando il metodo c.registerFrame( displayFrame).
Il display3D utilizza le librerie Java3D che verranno esposte nel
prossimo paragrafo.
I fields portrayals sono classi responsabili del disegno lasciando
all’utente la manipolazione degli oggetti conservati al loro interno.
51
Il portrayal3D che ho utilizzato nella mia simulazione è
sim.portrayal3d.continuous.ContinuousPortrayal3D che è il portrayal
di default per il campo Continuous3D.
Per attaccare il display3D con il portrayal3D si utilizza il metodo
display.attach(housePortrayal,"house").
Una rappresentazione del display3D è fornita in figura 4.10.
Figura 4.10 (Visualizzazione del display3D)
Il metodo quit( ) è chiamato quando console viene chiusa e si occupa
di chiudere il display e il relativo frame associato.
52
Il metodo start( ) viene chiamato quando si preme il pulsante play
della console. Il metodo load( ) invece viene chiamato quando la
simulazione è caricata da un file di controllo.
In genere questi 2 metodi fanno la stessa cosa quindi si utilizza il
metodo setupPortrayals( ) che esegue le operazioni necessarie.
Tale metodo svolge varie operazioni:
display.destroySceneGraph( ): rimuove dalla scena tutto il
contenuto precedente.
housePortrayal.setField( m.house): indica che il portrayal deve
raffigurare il field del modello ovvero m.house. Questa
operazione va eseguita dopo aver distrutto la scena grafica
perché potrebbe tentare di modificare gli oggetti che Java3D ha
in comune con gli oggetti della scena grafica e che non possono
essere modificati.
display.reset ( ) e display.createSceneGraph( ): consentono al
display3D di ricostruirsi dopo aver distrutto la scena grafica.
Quando si verifica il reset del display lui si registra
automaticamente con la GUIState per essere continuamente
aggiornato ad ogni step.
Il metodo createScene( ) si occupa di creare la struttura di base della
casa cioè le mura.
Infine il metodo creaPavimento( ) si occupa di disegnare il pavimento
della casa caricandolo da una texture.
53
4.3.2 Altre classi grafiche
Gli altri componenti della casa vengono disegnati a parte ognuno in
una classe apposita. Le varie classi vengono definite per distinguere le
tipologie di oggetti contenuti nella casa e per effettuare il disegno su
misura. I componenti della casa sono aggiunti al field house e
collocati nella posizione idonea.
Le varie classi utilizzate sono:
Armadio.java : disegna l’armadio e lo colloca nella camera.
Bagno.java : effettua il disegno dei sanitari del bagno.
Cucina.java : effettua il disegno dei componenti della cucina
che comprende il frigorifero, i fornelli, il lavandino e i mobili.
Divano.java : disegna il divano e lo colloca in salotto.
Door.java : disegna le porte e le colloca nelle posizioni idonee.
Finestra.java : disegna le finestre e le colloca nelle posizioni
idonee.
Letto.java : disegna il letto e lo colloca nella camera.
Sedia.java : disegna le sedie e le colloca nelle posizioni idonee
all’interno della casa.
Tavolo.java : disegna i tavoli e li colloca nelle giuste posizioni.
Telefono.java : disegna il mobile con il telefono sopra e lo
colloca nel salotto.
Tv.java : disegna il televisore lcd e lo colloca nel salotto.
Ognuna delle classi sopra citate estende la classe SimplePortrayal3D
che non fornisce un disegno di default ma è il programmatore che
decide come disegnare quel determinato componente.
Il disegno di ogni componente avviene utilizzando la classe loader di
java3D che consente di caricare un file .obj che contiene la
realizzazione grafica dell’oggetto da disegnare. La classe loader verrà
54
esposta in maniera più approfondita nel paragrafo successivo relativo
alle librerie java3D.
Un esempio di come avviene il caricamento della grafica è mostrato
nel codice seguente:
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import sim.portrayal3d.SimplePortrayal3D;
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
public class Bagno extends SimplePortrayal3D {
public TransformGroup getModel(Object obj, TransformGroup
j3dModel)
{
if(j3dModel==null){
j3dModel = new TransformGroup();
TransformGroup tG1=new TransformGroup();
Transform3D t3d=new Transform3D();
t3d.setScale(20.0);
tG1.setTransform(t3d);
j3dModel.addChild(tG1);
ObjectFile f=new ObjectFile(ObjectFile.RESIZE);
try
{
Scene s=f.load("bagno.obj");
BranchGroup b=s.getSceneGroup();
tG1.addChild(b);
b.compile();
}
catch (Exception e) {System.out.println(e);}
}
return j3dModel;
}
}
55
4.4 Librerie Java3D
Java3D è un interfaccia di programmazione grafica in 3D per la
costruzione di applicazioni e applet Java. Java3D è una libreria per
l'interfacciamento ad un sistema tridimensionale grafico e sonoro.
Basato sulla portabilità del java. Essa fornisce agli sviluppatori di alto
livello costrutti per creare e manipolare la geometria 3D .
Le schede 3D producono oggi grafica interattiva paragonabile agli
effetti speciali cinematografici. Java è uno standard di sviluppo
consolidato, potente e stabile.
Il livello più basso del Java3D si basa sulle librerie come Direct3D,
OpenGL, QuickDraw3D, e XGL…. Java 3D introduce alcuni concetti
non comunemente considerati come parte dell’ambiente grafico
3D come ad esempio il suono spaziale.
Java 3D è stato progettato con diversi obiettivi in mente :
Raggiungere elevate prestazioni: il rendering è gestito
automaticamente. Il programmatore decide solo “cosa”
disegnare mentre Java3D decide “come” disegnarlo.
Integrazione con Java : core e portabilità
Fornire una serie di funzioni interessanti per creare mondi 3D.
Fornire un elevato livello di programmazione object-oriented
che consente agli sviluppatori di implementare sofisticate
applicazioni e applet rapidamente.
Forza industriale: non solo semplici applet3D ma anche
applicazioni molto più complesse.
Questo permette a java3D di ospitare una vasta gamma di formati di
file.
56
Java3D supporta un ampio range di applicazioni:
Simulazione 3D.
Sistemi CAD/CAM.
Visualizzazione Scientifica.
Desktop 3D.
Videogame.
Ecc..
4.4.1 Scene Graph
L’applicazione costruisce i singoli elementi grafici come oggetti
distinti e poi li collega insieme in una struttura chiamata scene graph.
La scena grafica contiene una descrizione completa di tutta la scena,
ciò include
la geometria dei dati, gli attributi
e tutte le altre
informazioni utili.
Una scena grafica è un albero che contiene i dati di scena. I children
sono le forme, le luci, suoni ecc…. I parents sono gruppi di children
e altri parents. Questo definisce un raggruppamento gerarchico di
forme. Il programmatore decide “cosa disegnare” mentre java3D
decide “come” disegnarlo per ottimizzare il rendering.
Un albero si compone di nodi e archi. I nodi sono oggetti java3D
invece gli archi rappresentano due tipi di relazioni tra oggetti:
relazione padre-figlio oppure reference.
Terminologia della scene graph :
1. Node : elementi della scena grafica. Le sottoclassi
costruiscono una scena grafica.
Leaf node: nodi senza figli (forme, luci, suoni, ecc…)
57
Group nodes: nodi con figli (branch , transform ,
switches , ecc…)
2. Node Component : insieme di attributi di un nodo
Geometria della forma;
Colore;
Suoni;
I node component sono collegati alla scena grafica tramite reference.
Class Hierarchy
java.lang.Object
javax.media.j3d.SceneGraphObject
javax.media.j3d.Node
javax.media.j3d.Group
javax.media.j3d.Leaf
javax.media.j3d.NodeComponent
Terminologia dell’universo :
Virtual Universe : raccolta di scene grafiche. In genere uno per
ogni applicazione.
Locale : posizione in cui l’universo mette la scena grafica. In
genere uno per ogni universo.
Branch Graph : una scena grafica. In genere diverse scene
grafiche per ogni locale.
Normalmente le scene grafiche sono divise in due tipi di branch
graph:
1. Content Branch : (forme , luci , ecc..) in genere più
content branch per locale.
2. View Branch : visualizzazione delle informazioni. In
genere uno per ogni universo.
Tale divisione è facoltativa infatti content e view possono appartenere
anche allo stesso ramo.
58
SimpleUniverse è un oggetto contenente un virtualUniverse, un locale
e una view branch graph.
La procedura di creazione di un simpleUniverse è:
1. Creare un oggetto Canvas3D.
2. Creare un oggetto SimpleUniverse e collegarlo al canvas3D.
3. Personalizzare l’oggetto simple universe.
4. Costruire uno o più content branch graph.
5. Compilarli.
6. Collegarli al locale del simple universe.
L’aggiunta di un branch graph nel locale ( o nel simple universe) li
rende dei nodi live (drawable)
Rimuovere il branch graph dal locale invece ha l’effetto contrario.
Gli oggetti vivi possono essere renderizzati e i loro parametri non più
modificabili. Per rendere un parametro modificabile anche quando
l'oggetto è vivo, la corrispondente capability deve essere impostata su
“modificabile” prima che l'oggetto stesso diventi vivo.
Il metodo isLive( ) restituisce true se il nodo è live, false altrimenti.
Il metodo compile( ) di branchGroup compila il branch ottimizzando il
rendering. Quando si invoca tale metodo java3D converte l’intero
branch graph in una rappresentazione interna molto più efficiente.
Le capacità possono essere cambiate solo se il nodo è live, inoltre tali
capacità vengono anche ereditate.
59
4.4.2 Shape3D
Shape3D è descritto da una geometria (forma) e da un aspetto
(appearance : colore, trasparenza, ecc). Java3D fornisce anche altri
tipi di geometria tra cui raster geometry e text geometry .
Shape3D estende la classe Leaf.
java.lang.Object
javax.media.j3d.SceneGraphObject
javax.media.j3d.Node
javax.media.j3d.Leaf
javax.media.j3d.Shape3D
I metodi di Shape3D sono:
Shape3D( )
Shape3D(Geometry geometry, Appearance appearance)
void setGeometry( Geometry geometry )
void setAppearance( Appearance appearance )
Costruire una shape è come collegare un insieme di coordinate 3D.
Una rappresentazione degli assi cartesiani del java3D è fornita nella
figura 4.11.
Y
X
Z
Figura 4.11 (Assi cartesiani in Java3D)
60
Il vertice descrive un angolo di un poligono e contiene diverse
informazioni tra cui la coordinata 3D , colore , superfici normali e
coordinate di texture.
La coordinata 3D è necessaria mentre le altre sono facoltative.
I diversi tipi di geometria sono:
GeometryArray consente di costruire punti, linee, triangoli e
quadrilateri.
GeometryStripArray consente il riuso dei vertici per migliorare
le prestazioni.
IndexedGeometryArray indicizza i vertici per poterli riutilizzare
a piacimento tutte le volte che si vuole.
GeometryInfo permette di definire dei poligoni arbitrari.
L’aspetto di una figura 3D definisce come effettuare il render della
geometria ovvero il colore, trasparenza, spessore delle linee e altro.
Tali caratteristiche sono incapsulate nella classe Appearance .
Gli attributi sono distinti in :
Material: controlla l’ambiente, emissione, il colore speculare e
il fattore di lucentezza.
ColoringAttributes: controlla il colore intrinseco della figura.
TransparencyAttributes: controlla il valore e le modalità di
trasparenza.
PointAttributes: gestisce le dimensioni del punto e l’antialiasing.
LineAttributes: gestisce il rendering delle linee.
PolygonAttributes: gestisce il rendering dei poligoni.
Texture: gestisce la texture dell’immagini e le modalità di
rendering.
61
4.4.3 Grouping shapes
Una scena grafica è una gerarchia di gruppi. Java3D ha diversi tipi di
gruppi. Ogni gruppo gestisce una lista di nodi figli. Tutti i gruppi
condividono gli attributi ereditati dalla classe Group.
È possibile aggiungere, inserire, rimuovere e ottenere i children in un
gruppo. I children sono implicitamente numerati a partire da zero.
Un gruppo può avere qualsiasi numero di children.
Java3D ordina le figure per migliorare l'efficienza.
La gerarchia è la seguente:
java.lang.Object
javax.media.j3d.SceneGraphObject
javax.media.j3d.Node
javax.media.j3d.Group
javax.media.j3d.BranchGroup
javax.media.j3d.OrderedGroup
javax.media.j3d.DecalGroup
javax.media.j3d.SharedGroup
javax.media.j3d.Switch
javax.media.j3d.TransformGroup
I grouping node di java3D sono:
BranchGroup estende Group e crea un branch graph. Il branch
graph può essere aggiunto ad un locale, può essere compilato,
può essere un child di un altro nodo e può eventualmente
distaccarsi dalla madre. Quando un branchGroup viene
aggiunto ad un locale diventa vivo.
TransformGroup estende group e consente di costruire un
nuovo sistema di coordinate. La trasformazione è descritta
tramite una Transform3D definita internamente come una
matrice 4x4. È possibile impostare direttamente la matrice ma
62
in genere si preferisce usare i metodi messi a disposizione dalla
classe. Le operazioni che consente di eseguire sono:
o Traslazione: sposta il sistema di coordinate e le sue
forme.
o Rotazione: orienta il sistema di coordinate e le sue forme.
È possibile ruotare lungo l’asse X,Y,Z oppure lungo un
asse arbitrario.
o Scaling: aumenta o riduce le proporzioni del sistema di
coordinate.
OrderedGroup estende Group e consente di eseguire il render
dei children in ordine.
Switch estende Group e consente di selezionare zero, uno o più
children di cui fare il render.
SharedGroup estende Group e crea un gruppo di forme che
possono essere condivise. Non viene aggiunto direttamente alla
scena grafica ma è referenziato da uno o più leaf group.
4.4.4 Luci direzionali
Java3D illumina gli oggetti in base ad una combinazione delle
proprietà degli oggetti e delle luci dell’universo virtuale. Java3D usa
un modello di illuminazione che approssima il modello fisico reale.
L’equazione del modello di illuminazione dipende da tre vettori:
La normale alla superficie (N)
La direzione della luce (L)
La direzione dell’osservatore (E)
63
Figura 4.12 (Modello di illuminazione)
Ovviamente nell’equazione entrano in gioco anche le proprietà
dell’oggetto. Anche se il modello di illuminazione è basato su quello
fisico alcuni fenomeni fisici non vengono modellati.
L’API java3D fornisce diverse classi per le luci, ogni classe deriva
dalla classe astratta Light.
Le varie classi sono:
AmbientLight: fornisce una luce della stessa intensità in tutte le
direzioni e in tutte le posizioni.
DirectionalLight: approssima sorgenti di luce distanti (ad
esempio il sole) e illumina in una sola direzione con la stessa
intensità in maniera indipendente dalla distanza.
PointLight: è una sorgente di luce puntiforme che si diffonde
in tutte le direzioni e la cui intensità diminuisce con la distanza.
SpotLight: è una sottoclasse di PointLight e aggiunge il
concetto di direzione e concentrazione della luce.
In genere conviene usare due luci direzionali per illuminare
l’ambiente perché sono più semplici da usare rispetto alle altre.
Nella mia simulazione infatti ho usato 2 luci direzionali. Il codice
relativo è:
//Aggiunge una luce direzionale
DirectionalLight lightD1=new DirectionalLight();
lightD1.setColor(new Color3f(1.0f,1.0f,0.9f));
lightD1.setDirection(new Vector3f(1.0f,1.0f,1.0f));
64
lightD1.setInfluencingBounds(bounds);
objRoot.addChild(lightD1);
//Aggiunge un'altra luce direzionale
DirectionalLight lightD2=new DirectionalLight();
lightD2.setColor(new Color3f(1.0f,1.0f,1.0f));
lightD2.setDirection(new Vector3f(-1.0f,-1.0f,-1.0f));
lightD2.setInfluencingBounds(bounds);
objRoot.addChild(lightD2);
4.4.5 Classe loader
La realizzazione di forme 3D utilizzando le classi di base è molto
complessa in quanto bisogna definire tutti i possibili vertici, le
superfici, le normali alle superfici ed un'altra serie di attributi
fondamentali.
Per modellare l’ambiente grafico della mia simulazione ho utilizzato
la classe loader che legge un modello da un file e ne crea la sua
rappresentazione java3D.
Il package com.sun.j3d.loaders fornisce gli strumenti per caricare
contenuti 3D creati con altre applicazioni (3DStudio, Blender, Art of
Illusion, ecc…). Poiché esistono moltissimi formati 3D (obj, vrml,3ds,
ecc…) e possono sempre essere inventati di nuovi allora java3D mette
a disposizione un’interfaccia generica per la creazione di caricatori di
file. Le operazioni da svolgere per caricare un file utilizzando un
loader sono semplici:
Trovare un loader compatibile con il formato del file.
Caricare il file e assegnare il risultato ad un oggetto Scene.
Inserire lo scene nello scene graph.
Nella mia simulazione 3D ho utilizzato dei file in formato .obj
realizzati con l’applicazione Art of Illusion.
65
Art of Illusion è un programma open source per la modellazione, il
rendering, il texturing, il ray tracing di immagini ed animazioni
tridimensionali. Lo scopo principale di Art of Illusion è quello di
costituire un potente strumento di modellazione 3D con un'interfaccia
grafica che apporta miglioramenti a quelle presenti in altri programmi
di computer grafica.
66
5. CONCLUSIONI
Il progetto che ho sviluppato mi ha consentito di estendere le mie
conoscenze nell’area dell’intelligenza artificiale, in quella della
grafica tridimensionale e ha approfondito notevolmente le mie
competenze con il linguaggio di programmazione java e con la
simulazione multi-agente mediante la piattaforma Mason.
L’obiettivo della mia simulazione è quello di monitorare la vita
dell’anziano attuando quindi una forma di ambient assisted living.
Nella realtà questo obiettivo può essere realizzato utilizzando gli
strumenti tecnologici che io ho rappresentato graficamente nella mia
simulazione cioè sensori ambientali, sensori vitali e un’assistente
virtuale autonomo con voce sintetizzata.
Nel mio progetto comunque gli agenti non sono completamente
autonomi in quanto le azioni compiute dall’anziano sono predefinite e
anche il supporto fornito dall’assistente virtuale è deciso a priori.
Quindi spero che il mio lavoro possa essere un punto di partenza per
realizzare delle simulazioni autonome in cui gli agenti decidono le
azioni da compiere in base alle loro capacità decisionali.
Inoltre spero anche che il mio lavoro con il Mason possa essere di
aiuto ad altri studenti che cercano di utilizzare questa piattaforma di
simulazione multi-agente non semplice da capire per programmatori
inesperti.
Infine vorrei ringraziare il prof. Dragoni che mi ha dato la possibilità
di svolgere attività di tirocinio presso il DIIGA.
67
6. RIFERIMENTI
[1]
George Mason University, Department of Computer Science,
Washington,
MASON
Multi-agent
Simulation
Toolkit
http://www.cs.gmu.edu/ ~eclab/ projects/mason/.
[2]
Sean Luke. ECJ 11: A Java evolutionary computation library.
http://cs.gmu.edu/_eclab/projects/ecj/, 2004.
[3]
Evolutionary Computation Laboratory Department of Computer
http://cs.gmu.edu/~eclab/.
[4]
Center for Social Complexity http://socialcomplexity.gmu.edu.
[5]
Steve Lytinen (http://condor.depaul.edu/~slytinen/) e Steve
Railsback (Lang, Railsback & Associates): How to Set Up
MASON in Eclipse.
[6]
Liviu Panait and Sean Luke. A pheromone-based utility model for
collaborative foraging. In Proceedings of the Third International
Joint Conference on Autonomous Agents and Multi Agent
Systems (AAMAS-2004), 2004.
[7]
E. Bonabeau, M. Dorigo, and G. Theraulaz. Swarm Intelligence:
From Natural to Artificial Systems. Santa Fe Institute Studies in
the Sciences of Complexity. Oxford University Press, 1999.
[8]
The Java 3D API Specification. Version 1.2, April 2000.
http://java.sun.com/products/java-media/3D/forDevelopers/
J3D_1_2_API/j3dguide/index.html.
[9]
Henry A. Sowizral, David R. Nadeau : Introduction to
Programming with Java 3D.
[10] Burattini E. , Cordeschi R. Intelligenza Artificiale: manuale per
le discipline della comunicazione. Ottobre 2001.
68
[11] Deitel H.M., Deitel P.J. : Java Fondamenti di programmazione ,
terza edizione, ottobre 2005.
[12] Deitel H.M., Deitel P.J. : Java Tecniche avanzate di
programmazione , terza edizione.
[13] Mason’s documentation and tutorial
http://www.cs.gmu.edu/~eclab/projects/mason/docs/
[14]
Sean Luke, Claudio Cioffi-Revilla, Liviu Panait, and Keith
Sullivan. MASON: A New Multi-Agent Simulation Toolkit. 2004.
Proceedings of the 2004 SwarmFest Workshop.
[15]
Claudio Cioffi-Revilla, Sean Paus, Sean Luke, James Olds, and
Jason
Thomas.
Computational
Mnemonic
Agent-Based
Structure
Simulation
and
Sociality:
A
Model. 2004. In
Conference on Colective Intentionality IV.
[16] Sean Luke, Claudio Cioffi-Revilla, Liviu Panait, Keith Sullivan,
and Gabriel Balan. MASON: A Multi-Agent Simulation
Environment. 2005. In Simulation.
69
7. APPENDICE : LIBRERIE DEL MASON
La piattaforma di simulazione Mason offre molte librerie che hanno
diverse relazioni tra di loro.
Uno schema generale sull’organizzazione del Mason è esposto nella
figura 7.1.
Figura 7.1 ( Schema generale dei componenti Mason)
70
Una rappresentazione dei componenti del modello e le relazioni con
l’interfaccia grafica sono mostrate in figura 7.2.
Figura 7.2 (Relazioni tra modello e GUI)
71
Una panoramica dei fields offerti dalle librerie del Mason è mostrata
in figura 7.3.
Figura 7.3 ( Fields del Mason)
72
Una panoramica dei fields portrayal3D offerti dalle librerie Mason è
mostrata in figura 7.4.
Figura 7.4 ( Fields portrayals3D)
73
Infine una panoramica dei simple portrayal3D è mostrata in figura 7.5.
Figura 7.5 ( Simple portrayals3D)
74
8. INDICE DELLE FIGURE
3.1 Architettura del Mason
11
3.2 Procedura del checkpointing
12
3.3 Componenti del Mason
16
3.4 Installazione di Mason in Eclipse
20
3.5 Creazione di un nuovo progetto
21
3.6 Avviare un progetto
23
4.1 Assistente virtuale e sensore
24
4.2 Panoramica della casa
25
4.3 Panoramica della cucina
26
4.4 Panoramica del bagno
26
4.5 Panoramica della camera
27
4.6 Panoramica del salotto
27
4.7 Anziano con il figlio
29
4.8 Finestra di visualizzazione
45
4.9 Console del mason
50
4.10 Visualizzazione del display3D
52
4.11 Assi cartesiani in java3D
60
4.12 Modello di illuminazione
64
7.1 Schema generale dei componenti Mason
70
7.2 Relazioni tra modello e GUI
71
7.3 Fields del Mason
72
7.4 Fields portrayals3D
73
7.5 Simple portrayal3D
74
75