UNIVERSITÀ DEGLI STUDI DI TRENTO
Facoltà di Scienze Matematiche, Fisiche e Naturali
Corso di Laurea (triennale) in Informatica
Elaborato Finale
Costruzione di un'interfaccia-utente per Lavagne Interattive
Multimediali nel caso di simulazioni bidimensionali di fisica
Relatore:
Marco Ronchetti
Laureando:
Nicola Dorigatti
Anno Accademico 2007-2008
Indice generale
Indice delle illustrazioni
ii
Capitolo 1: Introduzione
1
Capitolo 2: Lavagne Interattive Multimediali
3
2.1
L.I.M. a tecnologia analogico-resistiva ............................................................................ 6
2.2
L.I.M. a tecnologia laser .................................................................................................. 7
2.3
L.I.M. a tecnologia elettromagnetica ............................................................................... 8
2.4
L.I.M. a tecnologia ottico-infrarossa ................................................................................ 9
2.5
L.I.M. a tecnologia ultrasonica ....................................................................................... 11
Capitolo 3: Scrittura di codice per L.I.M.
13
3.1
Descrizione API Java ..................................................................................................... 14
3.2
Considerazioni su User Interface ................................................................................... 21
3.3
Possibili soluzioni .......................................................................................................... 22
3.3.1 - Il “menu di penna” ................................................................................................. 22
3.3.2 - Handwriting Recognition ....................................................................................... 23
3.3.3 - Controllo tramite Gestures ..................................................................................... 24
Capitolo 4: Fisica 2D
4.1
27
Pacchetti di fisica 2D disponibili ................................................................................... 29
4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 -
Box2D ................................................................................................................... 29
JBox2D .................................................................................................................. 31
Phun .................................................................................................................... 31
Tokamak ................................................................................................................ 32
Phyz ....................................................................................................................... 34
4.2 Analisi delle librerie ....................................................................................................... 35
Capitolo 5: Descrizione dell'architettura
37
5.1
“Menu di penne” sviluppato .......................................................................................... 37
5.2
Cattura degli eventi generati dalla LIM ......................................................................... 45
5.3
Interfacciamento a JBox2D ............................................................................................ 49
Capitolo 6: Caso d'uso: Smart Box 2D
53
Capitolo 7: Conclusioni
65
Bibliografia
67
i
Indice delle illustrazioni
Figura 2.1........................................................................................................................................4
Figura 2.2........................................................................................................................................5
Figura 2.3........................................................................................................................................7
Figura 2.4........................................................................................................................................9
Figura 2.5......................................................................................................................................10
Figura 2.6......................................................................................................................................11
Figura 3.1......................................................................................................................................20
Figura 3.2......................................................................................................................................23
Figura 4.1......................................................................................................................................30
Figura 4.2......................................................................................................................................32
Figura 4.3......................................................................................................................................33
Figura 4.4......................................................................................................................................34
Figura 5.1......................................................................................................................................44
Figura 6.1......................................................................................................................................54
Figura 6.2......................................................................................................................................60
Figura 6.3......................................................................................................................................61
Figura 6.4......................................................................................................................................62
Figura 6.5......................................................................................................................................63
ii
Capitolo 1: Introduzione
Nel corso degli anni lo sviluppo delle applicazioni ha visto crescere sempre di più il contributo degli
utenti finali. Attraverso questo contributo si è andati verso una modifica radicale dei programmi,
rendendoli sempre più interattivi e di facile utilizzo. Di pari passo è aumentata l'offerta delle
periferiche di input multimediali, capaci sempre più di semplificare le azioni più o meno comuni
dell'utente che fa uso del calcolatore. Di conseguenza il bisogno di applicazioni interattive è
aumentato ulteriormente, con la necessità di adattare il software a queste nuove periferiche.
Un'interfaccia utente che sia semplice da comprendere e sfruttare permette quindi un uso migliore
di questi strumenti di input anche da parte di coloro che sono meno esperti o non conoscono le
periferiche in questione. Il fine di questa tesi è quindi l'analisi di una soluzione a questa necessità
nel caso delle lavagne interattive multimediali, ed in seguito lo sviluppo del sistema ideato in
precedenza, associando ad esso un software che fa uso delle sue caratteristiche. Il problema richiede
innanzitutto un'analisi dell'approccio grafico da elaborare, ponendo contemporaneamente attenzione
alle tecniche da implementare per sfruttare gli input della lavagna interattiva. Una volta creata
l'interfaccia si passerà alla cattura degli input che verranno associati a specifiche azioni del software
sviluppato che nel nostro caso è rappresentato da un simulatore di ambiente fisico bidimensionale.
Nel prossimo capitolo verranno analizzati con attenzione gli strumenti di input utilizzati (le lavagne
interattive multimediali), mostrandone le diverse tipologie a disposizione, e differenziando le varie
tecnologie implementate al loro interno.
Nel terzo capitolo l'attenzione sarà maggiormente posta sulle potenzialità messe a disposizione dalle
periferiche scelte, analizzando gli strumenti messi a disposizione dal costruttore delle lavagne.
Verranno quindi verificati i requisiti necessari all'interfaccia grafica per poter essere adottata in
questo ambito, proponendo ed approfondendo in seguito pregi, difetti ed attuabilità di alcune
soluzioni al problema.
Nel capitolo quattro troviamo la descrizione della libreria che verrà associata all'interfaccia grafica
per ottenere la soluzione finale. Inizialmente sarà presentata una panoramica dei pacchetti di fisica
bidimensionale disponibili, procedendo quindi ad una breve analisi di alcuni di quelli reperibili
1
attraverso internet, per poi valutare quale tra di essi può essere adottato nel programma finale.
Nel quinto capitolo verrà descritto lo sviluppo dell'interfaccia creata, utilizzabile come libreria
adattabile a contesti diversi e completamente personalizzabile. Mostreremo inoltre le tecniche
utilizzate per avere una corrispondenza fisico-grafica tra lavagna (superficie e strumenti) e
applicazione sviluppata. Infine mostreremo nello specifico i metodi adottati per lo scambio di dati
tra simulatore fisico utilizzato ed interfaccia per la lavagna.
Nel capitolo sei vedremo in dettaglio le caratteristiche e le tecniche implementate nel programma
finale (SmartBox2D), analizzando il funzionamento di alcune particolari azioni come la modifica
delle proprietà degli oggetti fisici, approfondendo la associazione tra gli eventi generati attraverso la
lavagna interattiva e la creazione degli oggetti che verranno inseriti all'interno del motore fisico.
2
Capitolo 2: Lavagne Interattive Multimediali
Le lavagne interattive multimediali (LIM) sono dei dispositivi elettronici studiati e ideati
principalmente per un uso didattico. Con la crescente capacità delle nuove generazioni di interagire
ed utilizzare computer e dispositivi elettronici questo tipo di lavagne aiuta l’apprendimento,
coinvolgendo l’attenzione degli studenti[1]. Nonostante la base prettamente didattica, le LIM
possono essere utilizzate per qualsiasi fine e, tra le varie applicazioni, va citato sicuramente l'uso
nelle conferenze, dove una lavagna che permette la modifica e l'evidenziazione di concetti e
immagini è sicuramente uno strumento utile se non, al giorno d'oggi, indispensabile[2].
Vi sono in commercio diversi tipi di LIM, ognuna con caratteristiche diverse ma in linea generale
tutte sono molto simili tra loro, differenziandosi particolarmente per la tecnologia di funzionamento.
Le dimensioni sono simili a quelle di una lavagna tradizionale ma al posto della classica superficie
in ardesia, troviamo una area a disposizione dell'utente che può essere:
–
–
Un pannello sensibile al tocco (lavagne a proiezione frontale).
Uno schermo di vetro (lavagne a retroproiezione).
Per ciò che riguarda la prima tipologia, come si può vedere in figura 2.1, la lavagna è costituita da
una superficie bianca e da un proiettore posto nella parte superiore, solitamente incorporato nel
corpo della lavagna stessa. Toccando il pannello in un determinato punto si invierà al computer, in
base alla tecnologia utilizzata ed allo strumento con cui si effettua l'azione, un evento, indicante
strumento e punto di contatto.
Il computer e la lavagna sono nella maggior parte dei casi connessi attraverso cavo dati USB o
tramite connessione senza fili (Bluetooth), ma non sono collegati direttamente. La LIM contiene
difatti al suo interno un controller, responsabile della ricezione dei dati riguardanti l'azione, del
calcolo del punto di contatto, e dell'invio al software delle informazioni necessarie a quest'ultimo
per eseguire un comando precedentemente stabilito dall'utente.
Il maggior vantaggio di questa tecnologia, è dato in gran parte dalla facilità di montaggio e dal poco
spazio occupato, con il difetto però che, essendo l'immagine proiettata, è necessaria una
3
calibrazione dello schermo ed in aggiunta, si può facilmente incontrare il problema dell'effetto
ombra, classico nell'ambito dei proiettori.
Figura 2.1: Lavagna Interattiva Multimediale a proiezione frontale.
Nella parte superiore dell'immagine si può notare il proiettore,
ancorato al corpo della lavagna, nella parte inferiore invece, il
gruppo contenente pennarelli, pulsanti per tastiera e tasto destro e
cancellino.
Le lavagne a retroproiezione invece, sono caratterizzate da un ingombro maggiore, le dimensioni
sono simili ad un televisore a tubo catodico di circa 40 pollici (tale dato può variare per ogni tipo di
modello).
Le maggiori dimensioni sono causate dal motivo seguente: all’interno dello chassis, è presente un
proiettore (come si può vedere in figura 2.2) che mostra l’immagine del desktop sullo schermo
tramite riflessione interna, ed è quindi necessario dello spazio per inserire proiettore ed i due
specchi per la riflessione dell’immagine.
Lo schermo è, guardandolo esternamente, una semplice superficie di vetro sulla quale il contatto
non viene differenziato per l'utente rispetto al contatto con un qualsiasi televisore, ma viene
comunque riconosciuto dalla lavagna tramite sensori posti nelle locazioni in cui le penne vengono
poggiate.
Per questa tipologia di lavagna, come per la precedente, la connessione tra essa ed il PC è affidata
alla trasmissione dati via cavo USB oppure ad una connessione Bluetooth.
Per questo tipo di LIM, le tecniche utilizzate per il riconoscimento del tocco possono essere molte,
in generale viene utilizzata la tecnologia ottico-infrarossa, ma in nessun caso quella analogicoresistiva, poiché tale tecnica richiede (come vedremo in seguito nella sezione 2.1) due strati di
materiale non trasparente, quindi non permetterebbe il passaggio dell'immagine tra la parte interna e
quella esterna dello schermo.
4
Anche in questo caso, tra computer e lavagna troviamo il controller per il processamento delle
informazioni.
A vantaggio della tecnologia a retroproiezione, troviamo la libertà di posizionamento in quanto, non
è necessario il montaggio a parete, seppur sia permessa l'integrazione in essa [3]. Altro fattore a
favore delle lavagne a retroproiezione, è la differente tecnologia di riconoscimento dei contatti, la
quale può in molti casi permettere il riconoscimento di più punti di contatto simultaneamente,
rendendo quindi possibile lo sviluppo di applicazioni che fanno uso del multitouch, cioè l'uso della
lavagna di più persone simultaneamente.
Figura 2.2: LIM con tecnologia a retroproiezione. Come mostrato nella figura di
destra,il proiettore non mostra direttamente l'immagine sullo schermo, ma la proietta
su di un piccolo specchio, il quale, appoggiandosi ad un altro più grande mostra il
desktop sullo schermo.
Sulla superficie viene quindi proiettata l’immagine ottenuta da un computer collegato alla LIM,
permettendo così all’utente che utilizza tale lavagna, di avere un vero e proprio desktop su un’area
più grande di un classico monitor per PC.
Un’altra caratteristica è rappresentata dalla possibilità di utilizzare pennarelli appositi per poter
scrivere sul desktop, utilizzare il cancellino per cancellare ciò che si è scritto, oppure di poter
controllare il puntatore del mouse con le dita. Toccando infatti la superficie su cui l’immagine è
proiettata, si ha una risposta da parte del software abbinato alla LIM, il quale, se si sta utilizzando
un pennarello, riprodurrà sullo schermo quello che l’utente ha scritto o disegnato, se invece si
utilizza un dito od un qualsiasi altro oggetto, non appartenente agli strumenti della lavagna, si potrà
controllare il mouse.
Oltre alla semplice scrittura di note sul PC, è possibile sfruttare lo stesso per usi comuni,quali la
5
navigazione web, presentazioni (tramite plugin appositi è possibile scrivere le note con i pennarelli
direttamente nelle slide della presentazione) o avviare programmi appositamente scritti per l'uso con
le LIM.
Sulla base della tecnologia utilizzata per interagire con il computer si possono attualmente
classificare cinque tipi di lavagne interattive multimediali: analogico-resistive (sezione 2.1), laser
(sezione 2.2), elettromagnetiche (sezione 2.3), ottiche basate sull'infrarosso (sezione 2.4) ed ultrasoniche (sezione 2.5).
Verranno quindi passate in rassegna le varie tecniche, elencandone il funzionamento base per
ognuna e, quando possibile, aggiungendo un'immagine esplicativa per rendere più chiaro il
concetto.
2.1 L.I.M. a tecnologia analogico-resistiva
Le lavagne che utilizzano la tecnologia analogico-resistiva, sono composte esternamente da una
superficie bianca in poliestere sulla quale l’immagine è proiettata.
Internamente presentano due strati flessibili, rivestiti con un materiale resistivo e divisi tra loro da
un sottilissimo strato d’aria (dell’ordine di 2x10-3 millimetri). La pressione di dito, di una penna o
qualsiasi altro oggetto su un qualsiasi punto della lavagna, mette a contatto questi due strati resistivi
(figura 2.3); questo genera un segnale elettrico che viene inviato prima al controller integrato nella
lavagna, e da li, successivamente, al PC tramite l’interfaccia di collegamento tra i due dispositivi.
Tramite questa tecnologia è possibile effettuare un solo tocco per volta, ciò vuol dire che il
multitouch (uso contemporaneo di due mani o di più persone) non è possibile, difatti, il controller
nel caso in cui riceve più di una coordinata di contatto nello stesso istante, esegue un'interpolazione
tra i valori ricevuti, col risultato che, il software ottiene come punto interessato, la posizione a metà
tra le due posizioni scelte.
L'azione appena descritta, viene eseguita in tal modo a causa della metodologia di costruzione della
tecnologia stessa, poiché cliccando anche solo in un punto, fisicamente non si mettono a contatto gli
strati resistivi solo per quel pixel, ma anche per le posizioni circostanti (ciò è causato dalla
grandezza dello strumento utilizzato, che supera quella dei pixel), ed è quindi il controller che fa in
modo che il PC riceva le coordinate di contatto corrette, effettuando appunto l'interpolazione dei
punti di quella zona.
Il difetto appena descritto dunque riduce le possibili applicazioni della lavagna con questa
tecnologia, limitando di fatto i casi d'uso ad applicazioni a tocco singolo.
Senza il multitouch difatti, molte semplificazioni nell'uso dell'interfaccia vengono a mancare. Se
questa tecnica fosse utilizzabile, sarebbe possibile configurare ed implementare gestures particolari
per eseguire determinate azioni. Le gestures sono però eseguibili anche a tocco singolo, ma sono
più difficili da riprodurre correttamente e sono inoltre complesse da controllare.
Solitamente la risoluzione dello strato resistivo è di 4096x4096 DPI, caratteristica che rende
abbastanza preciso il riconoscimento dei punti di contatto.
6
Di seguito, possiamo vedere una rappresentazione schematica della tecnologia appena descritta.
Figura 2.3: Contatto su superficie basata sul riconoscimento analogico-resistivo. Da
come si può vedere nell'immagine, al momento del tocco con il dito (7) sulla superficie
esterna (1), il piccolo gap di aria (5) tra i due strati resistivi (3) viene a mancare,
creando cosi un segnale elettrico, che viene inviato al controller della lavagna (8). Per
completezza, segnaliamo uno strato flessibile di spessore tra la superficie
esterna/posteriore e la parte resistiva (2-4) e lo strato rigido posto nella parte
posteriore della lavagna (6).
2.2 L.I.M. a tecnologia laser
Per ciò che riguarda questa tipologia di lavagne, quattro laser infrarossi sono situati nei quattro
angoli della lavagna. Il fascio di luce laser investe la superficie utilizzata, senza tornare indietro al
punto di partenza.
Le penne o gli altri strumenti a disposizione utilizzati con questa tecnologia presentano sulla
superficie che va a contatto con lo schermo un materiale lucido, il quale riflette il fascio di luce
facendolo tornare alla sorgente, rendendo quindi possibile il riconoscimento delle coordinate
riguardanti il punto di tocco.
Il difetto più grosso di questa tecnologia è rappresentato per l'appunto dalla necessità di avere penne
e strumenti riflettenti la luce laser, limitando quindi l’uso della lavagna ai soli strumenti messi a
disposizione, e rendendo impossibile l’utilizzo delle dita per controllare il mouse, ostacolando la
possibilità di sfruttare la lavagna come desktop e con più utenti, poiché rende necessario il continuo
scambio degli strumenti necessari al suo utilizzo.
D'altra parte però, va detto che con questa tecnologia precisione e sensibilità sono molto alte e si
7
riescono ad evitare eventi non voluti come ad esempio il caso in cui si poggia erroneamente la mano
sulla lavagna; con la tecnologia laser tale evento non viene considerato evitando cosi il rilevamento
del contatto indesiderato.
2.3 L.I.M. a tecnologia elettromagnetica
Le lavagne interattive multimediali che sfruttano la tecnologia elettromagnetica contengono nella
parte posteriore della superficie esterna, una griglia cablata che interagisce con le penne per determinare le coordinate.
Ci sono quindi nello strato posteriore allo schermo sensori magnetici che reagiscono al contatto
(Figura 2.4) ed inviano messaggi al controller interno, da quest'ultimo dati e coordinate passano al
computer nel momento in cui la griglia cablata viene attivata dall'uso delle penne magnetiche.
Gli strumenti utilizzati per sfruttare questa tecnologia, possono essere attivi (a batterie) o passivi
(Non magnetici, sfruttano i segnali elettrici prodotti dalla lavagna). Per il primo caso, l'oggetto
utilizzato sfrutta l'energia delle batterie interne per creare un campo elettromagnetico che, al
momento del contatto con la lavagna, farà reagire la corrispondente parte di griglia. Nel secondo
caso invece, la superficie di contatto è sensibile sia alle penne attive, sia al semplice tocco di un
altro strumento, quindi i sensori vengono attivati con impulsi elettromagnetici, ma anche con
semplici contatti sulla superficie (ad esempio con un dito).
Con queste lavagne è possibile avere una simulazione totale (click, drag&drop, click destro)
dell’uso del mouse, tramite una tecnica molto simile a quella implementata nelle tavolette grafiche
per PC utilizzate da grafici e disegnatori professionisti.
La superficie utilizzata per il riconoscimento degli eventi, può essere come detto sensibile alla
pressione e può permettere il multitouch. Ad esempio, in molte LIM che sfruttano la tecnologia
elettromagnetica, il click destro del mouse è rappresentato dalla pressione di due punti vicini tra
loro; questa gesture è facilmente effettuabile con due dita.
Solitamente, la risoluzione delle celle utilizzate è di 30000 x 30000 DPI, dato che, confrontato con
quello precedentemente visto per la tecnologia resistiva (2.1), non può che far capire come la griglia
di cavi sensibili agli impulsi elettro-magnetici sia molto più precisa dei film resistivi visti in
precedenza. [4]
Di seguito, è possibile vedere una rappresentazione grafica della sezione di un angolo di una
lavagna che fa uso della tecnologia elettromagnetica, con una breve descrizione delle parti
caratteristiche.
8
Figura 2.4: Tecnologia Elettromagnetica: Come mostra la figura (sezione di un
angolo) la parte fondamentale di questo tipo di riconoscimento, è data dal reticolo di
cavi-sensori posto immediatamente dietro alla superficie esterna. Il tutto viene poi
irrobustito da una cornice solida e da un pannello posteriore in legno o altro
materiale a nido d'ape, il quale permette di aver una buona leggerezza ed un'ottima
robustezza.
2.4 L.I.M. a tecnologia ottico-infrarossa
Scrivendo o toccando sul di una superficie costruita per questo tipo di tecnologia, si genera un
riflesso di luce infrarossa che viene catturato da un sensore integrato nella lavagna. Il sensore è
solitamente incorporato nella cornice che fa da perimetro allo schermo. In caso di tocco, con penna,
dito o quant'altro, il sensore viene attivato, invia al software le informazioni riguardanti l’evento
accaduto. Il software della LIM, basandosi sui dati ricevuti calcola la locazione esatta in cui è
avvenuto l’evento ed esegue l'azione prevista dal programma che si sta utilizzando, o una scelta in
precedenza dall'utente. Questa tecnologia permette l’utilizzo di qualsiasi penna o strumento per la
scrittura, poiché non richiede particolari caratteristiche per quanto riguarda i marcatori utilizzati
(dito o penne).
Nel 2007, uno studente PhD dell’università Carnegie Mellon ha dimostrato che è possibile sfruttare
questa tecnologia per creare una lavagna interattiva senza particolari strumenti. Johnny Chung Lee
ha mostrato infatti che, utilizzando il sensore infrarosso presente nel controller di gioco della
console Nintendo Wii [5] è possibile utilizzare quest'ultimo come penna, senza alcuna specifica
superficie.
Oltre ai metodi sopracitati ne esistono altri per il riconoscimento del movimento della mano
(mediante trasmettitore led sulla base della penna con cui si scrive), oppure per il tracking di un
punto di luce laser presente su di una penna o di un telecomando (per esempio quelli dei proiettori),
con il vantaggio di avere una portabilità maggiore, e sciogliendo il vincolo della dimensione della
lavagna, poiché non è necessario alcun tipo di schermo con caratteristiche specifiche, ma è
9
sufficiente una superficie monocromatica e di colore diverso dal raggio generato dal telecomando.
Figura 2.5: Presentatore e Ricevitore Laser. Con soli questi due oggetti è possibile
eseguire la maggior parte delle azioni eseguibili con le altre tecnologie. Non è
possibile il multitouch, ma la portabilità è massima.
Da sottolineare, all’interno di questa categoria è la tecnologia DViT (Digital Vision Touch, Figura
2.6)[6] in fase di brevetto, ma già applicata ai suoi prodotti, da SMART Technologies Inc® che
sfrutta tre camere poste in tre dei quattro angoli dello schermo (due superiori ed uno inferiore) per
riconoscere il punto esatto in cui si sta operando, inviando al software proprietario i dati rilevati, il
quale tramite opportuni calcoli procederà al corretto rilevamento del punto di contatto. Oltre a ciò è
possibile anche il multitouch, con il quale ad esempio si possono eseguire gestures memorizzabili e
personalizzabili tramite il programma di controllo SMART. Un esempio di gesture è rappresentato
dal click destro del mouse, effettuabile toccando lo schermo con un dito, quindi con un altro dito
premere subito a destra del primo punto scelto.
Per ciò che riguarda il riconoscimento dello strumento utilizzato, le tre camere poste nella cornice si
occupano, oltre che a rilevare i dati della posizione, della cattura di un'immagine dell'oggetto che si
sta controllando, riconoscendone forma e colore e abbinandolo ad una relativa azione del software.
Questa tecnologia, che non richiede alcun tipo di schermo attivo (come può essere uno schermo
sensibile elettromagneticamente oppure uno analogico resistivo) ed è presente solamente per le
lavagne a retroproiezione e quelle a display piatto ( che quindi sfruttano uno schermo LCD).[7]
10
Figura 2.6: DViT (Digital Vision Touch): Lo schermo appare come un semplice vetro, non
presenta parti attive o sensori, poiché questi sono posti negli angoli (Figura destra).
2.5 L.I.M. a tecnologia ultrasonica
Questo tipo di tecnica per il rilevamento sfrutta trasmettitori e ricevitori ultrasonici. I primi sono
posti in due dei quattro angoli della cornice, i secondi sono situati negli angoli opposti ai
trasmettitori.
Sfruttando le onde ultrasoniche, trasmesse sulla superficie e riflesse da oggetti riflettenti posti nella
cornice della lavagna, è possibile creare una fitta griglia di onde che servirà a controllare qualsiasi
tocco. Andando appunto a contatto con un dito o con una penna, si causerà l’interruzione di una
zona di questa griglia, interrompendo quindi l'arrivo di un'onda al sensore, il quale informerà il
controller della LIM dell’accaduto. Dopo aver calcolato la posizione ottenuta in base a calcoli
relativi ai dati ricevuti, il controller invierà le coordinate al software che eseguirà un’opportuna
funzione (disegno o uso del mouse).
Da come si può intuire dalla precedente descrizione, anche con questa tecnologia si possono
utilizzare penne e strumenti senza particolari peculiarità. E' prevista inoltre la compatibilità con il
multitouch.
11
12
Capitolo 3: Scrittura di codice per L.I.M.
Dopo aver visionato le varie tecnologie a disposizione, i rispettivi limiti e caratteristiche delle
stesse, è possibile analizzare l'espandibilità delle lavagne, scrivendo codice sorgente in modo da
sviluppare programmi capaci di aumentare ulteriormente le potenzialità di questa tecnologia.[8]
Nel nostro caso ci siamo incentrati sulle lavagne SMART, per la precisione su quelle a proiezione
frontale integranti la tecnologia analogico-resistiva. Tale scelta non è stata dettata da particolari
esigenze ma dal fatto che tale lavagna era già a nostra disposizione e soddisfa le nostre richieste.
Questi modelli di lavagne grazie ad alcune librerie danno la possibilità di interfacciare gli eventi
della lavagna ad un programma scritto appositamente per essa. Per poter quindi sfruttare le
caratteristiche della lavagna nel proprio programma è necessario, all'interno del codice, richiamare
delle apposite funzioni.
Per prima cosa è necessario attivare una connessione tra PC e lavagna richiamando il metodo di
creazione dell'oggetto SBSDK (Smart Board Software Development Kit) che, sfruttando una
libreria DLL (da importare nel programma scritto) ottiene il numero di porta tramite il quale la
lavagna è connessa, ed abilita cosi correttamente lo scambio di dati tra software e controller della
lavagna.
Il passo successivo consiste nel comunicare all'oggetto SDK qual è la parte del programma
(graficamente) su cui abilitare la cattura degli eventi. Tramite le funzioni di interfacciamento tra PC
e lavagna, è infatti possibile abilitare il controllo delle azioni solo su una parte della finestra,
semplificando cosi la gestione dei dati riguardanti la posizione degli eventi. Catturando infatti le
azioni solo all'interno di un pannello e non su tutta la finestra, il Software Development Kit non
restituirà i punti di contatto relativi all'angolo sinistro della finestra, ma a quello del pannello
monitorato (il punto <0,0> risulta quindi il primo pixel in alto a sinistra nel pannello controllato
dall'applicazione).
E' quindi d'obbligo la chiamata della funzione di attacco (collegamento) alla finestra principale
dell'applicazione. Il passo successivo invece, consiste nel comunicare all'SDK il pannello su cui
effettuare il controllo delle azioni.
Assieme a tale oggetto, è necessario passare all'oggetto SBSDK anche un actionListener specifico
per la lavagna. Difatti per gestire il monitoraggio, e semplificare all'utente la cattura degli eventi, è
13
presente un'interfaccia che, dopo esser stata implementata, fa da listener (SBSDKListener) e
fornisce metodi per controllare ogni evento riguardante la lavagna ( se una penna viene rimossa o
posata nella sua sede, se il proiettore è acceso o meno, se, sfruttando il software apposito della
lavagna, sono abilitate azioni speciali per le penne).
Una volta effettuati questi piccoli passi (un esempio di codice java è rappresentato dal Codice 1) è
possibile sfruttare appieno la lavagna, si ha il controllo su tutte le modifiche di stato per gli oggetti
della lavagna, ed è possibile quindi personalizzare la risposta del PC a qualsiasi input proveniente
dalla LIM.
SBSDK sdk = new SBSDK();
sdk.attach( Window topFrame , boolean XMLAnnotations );
sdk.registerComponent( Component panel , SBSDKListener BoardListener );
Codice 1: Codice per la connessione alla Lavagna Interattiva SmartBoard.
Dapprima è necessario istanziare l'oggetto principale per l'interfacciamento con il
PC, quindi, si richiama il metodo attach, comunicandogli la finestra del programma
da monitorare. Una volta fatto ciò, la funzione registerComponent definisce il
pannello su cui controllare, tramite l'oggetto BoardListener, le azioni eseguite
dall'utente.
Quello che è stato mostrato fin'ora è la routine generica per abilitare l'ascolto degli eventi della
lavagna, valida per i linguaggi di programmazione supportati (C++, C#, VisualBasic, Java, Flash )
ma che può avere, in base al linguaggio scelto un'estensione più lunga e complessa come nel caso
del C#, oppure può essere semplice e veloce come per l'esempio visto, in Java.
Proprio grazie al fatto che il codice necessario è più veloce e leggibile, si è scelto di incentrarsi sul
linguaggio Java, il quale offre innumerevoli metodi e classi, soprattutto per ciò che riguarda
software multimediali ed ad alto tasso di interattività.
3.1 Descrizione API Java
Un ambiente di sviluppo che risulti semplice da programmare soprattutto per quel che riguarda la
parte interattiva-grafica è rappresentato dal linguaggio Java. Grazie a quest'ultimo è possibile
sviluppare applicazioni ad alto tasso interattivo e con una grafica semplice da utilizzare e
visualizzare, senza dover appoggiarsi a programmi o librerie esterne. L'unico pacchetto da includere
in un software interfacciato ad una LIM è quello appunto descritto nella sezione precedente.
La libreria “sbsdk.jar” fornita da SMART INC, accoppiata al file DLL, è sufficiente a mettere a
nostra disposizione tutti gli strumenti necessari a sviluppare la nostra applicazione interattiva.
14
Principalmente, la libreria è composta da una classe ed un'interfaccia da implementare, con in
aggiunta altre due classi, una statica contente campi di tipo static indicanti gli strumenti o le penne
della lavagna, l'altra rappresentate le informazioni del software SmartBoard installato nel PC.
La classe principale, come detto ad inizio capitolo è com.smarttech.board.sbsdk.SBSDK, che ha
la principale funzione di associare il codice che si sta scrivendo con il software Smart, e permette
inoltre di ricavare informazioni riguardo lo strumento in uso, alla sua dimensione o il colore della
penna, o di controllare lo stato della connessione di una o più lavagne, e di verificare se si sta
lavorando in modalità “projected” (con proiettore acceso), o “non-projected” (con proiettore
spento).
Per la connessione ad una o più lavagne il metodo della classe è:
boolean attach(Window topLevelWindow, boolean bSendXMLNote)
Con la chiamata alla funzione attach, si eseguirà l'associazione e la connessione tra la lavagna e la
finestra del software da controllare. Una volta specificata la finestra principale, ogni Component
che è contenuto al suo interno, è un possibile candidato all'associazione con un ascoltatore di eventi
(come vedremo in seguito) della lavagna.
Il secondo parametro di questo metodo rappresenta un flag utilizzato per decidere se si vogliono
ricevere informazioni in formato XML dal software-driver della LIM. Una volta effettuata la
connessione tra PC e lavagna, il metodo restituisce true e l'oggetto SDK a cui appartiene questa
funzione, abilita un flusso di dati sugli eventi avvenuti all'interno della finestra specificata.
void registerComponent(Component c, SBSDKListener l)
void unregisterComponent(Component c)
In seguito all'interfacciamento con la lavagna eseguito con la precedente funzione attach, la
chiamata a registerComponent associa l'ascoltatore di eventi SBSDKListener al componente
specificato. E' quindi possibile differenziare il comportamento del nostro programma in seguito
all'uso di un determinato strumento su quello specifico oggetto della finestra, permettendo la
creazione di interfacce complesse e con ampie possibilità di personalizzazione.
Prendiamo come esempio un bottone cliccabile dai pennarelli ed uno utilizzabile solo via mouse, è
possibile ottenere questo comportamento associando SBSDKListener solo sul primo dei due
pulsanti.
Analogamente, unregisterComponent permette di dissociare il listener al componente specificato in
15
fase di chiamata.
Per ricavare le informazioni sulla lavagna connessa e per poter verificare se, in caso di connessione
multipla, una determinata lavagna è connessa al PC o meno, si possono utilizzare i metodi seguenti:
int getBoardCount()
int getConnectedBoardCount()
boolean isABoardConnected()
Tramite getBoardCount si ottiene il numero di lavagne collegate fisicamente alla macchina, anche
nel caso che esse siano spente o non correttamente configurate. Per ottenere invece, il numero di
lavagne effettivamente funzionanti, è necessario richiamare il metodo getConnectedBoardCount che
restituisce appunto tale dato. isABoardConnected invece, ha l'utilità di controllare se almeno una
lavagna è collegata al PC; questa condizione va necessariamente verificata, prima di effettuare
qualsiasi tentativo di connessione tra software e controller.
int getBoardNumberFromPointerID(int iPointerID)
boolean isBoardProjected(int iPointerID)
Color getToolColor(int iPointerID)
int getToolType(int iPointerID)
int getToolWidth(int iPointerID)
Come è già stato detto in precedenza, le API in questione permettono la scrittura di codice per la
gestione di più lavagne. Fino ad ora, non è stato detto però come poter riconoscere e differenziare le
varie lavagne; ogni L.I.M. Smart, è caratterizzata da un identificativo iPointerID univoco. Tramite
questo ID, si possono ricavare numerose informazioni sulla lavagna corrispondente.
In caso di più lavagne utilizzate simultaneamente, l'oggetto che gestisce la connessione ad esse as­
segna, al momento del collegamento,l'indice di un array per ognuna di esse; tale indice è ottenibile
dalla funzione getBoardNumberFromPointerID.
16
Per verificare invece se si sta lavorando in modalità proiezione, tramite iPointerID è possibile
chiamare il metodo isBoardProjected, il quale, tramite valore booleano ci dirà la modalità utilizzata.
Per quello che riguarda invece le informazioni riguardanti gli strumenti utilizzati, i tre metodi
getToolColor, getToolType e getToolWidth in base al iPointerID ricevuto come parametro,
restituiscono rispettivamente il colore dello strumento (per il cancellino, il colore ottenuto è il
bianco), il tipo di oggetto in uso (le penne fanno parte del tipo 1, mentre il cancellino ha l'intero 2) e
lo spessore dell'oggetto (per le penne lo spessore standard è circa di 4 pixel, mentre per il cancellino
i pixel sono all'incirca 40).
Grazie a questi metodi, è possibile conoscere con esattezza cosa l'utente stia utilizzando con la
lavagna. Ogni funzione, si basa sulle risposte ricevute dal software-driver SMART, il quale
permette di modificare l'azione che ogni pennarello deve eseguire.
E' possibile infatti cambiare il colore attuale ad ogni penna, come ad esempio specificare il colore
grigio per la penna nera, oppure fare in modo che una determinata penna disegni un cerchio ad ogni
tocco, invece che il normale disegno a mano libera. In caso di modifiche di questo tipo, la chiamata
alla funzione getToolColor restituirà il colore grigio e non quello nero, mentre la funzione
getToolType avrà come valore di ritorno quello corrispondente al cerchio (per esempio 1 è il valore
della penna a mano libera, 2 il cancellino e così via).
Con i metodi appena visti, tramite iPointerID, si ricavano le informazioni del tool nel momento del
loro utilizzo. Di primo acchito quindi, sembra che sia sufficiente la classe appena vista per avere
tutti i dati necessari all'uso della lavagna, invece, è d'obbligo l'uso di SBSDKListener.
Implementando l'interfaccia del listener SmartBoard si possono personalizzare i metodi, quindi, ciò
che il nostro programma computa ad ogni evento della lavagna.
SBSDKListener fornisce vari metodi i quali vengono richiamati automaticamente al momento
dell'azione corrispettiva.
Gli eventi catturati coprono tutte le possibili azioni della lavagna, ed in particolare dobbiamo
segnalare innanzitutto quello che controlla la connessione/disconnessione con la lavagna:
void onBoardSettingsChange()
In caso di disconnessione della lavagna dal PC, o di cambio delle impostazioni dell'applicazionedriver SMARTBoard, questo metodo viene richiamato. Una sua corretta implementazione permette
il controllo e l'adattamento del software sviluppato ad ogni cambiamento della lavagna.
Passando ai metodi degli strumenti, ne troviamo alcuni che tra loro si assomigliano per ciò che
riguarda la firma. Tutti quanti infatti vengono richiamati ed eseguiti con un parametro solo,
iPointerID, che è lo stesso visto poco prima in questo capitolo.
17
Ogni metodo ha come prefisso nel nome la sillaba on, che tradotto dall'inglese vale come dire: “in
caso di”, e quindi il nome effettivo dello strumento causa della chiamata a questa funzione.
void onCircle(int iPointerID)
void onRectangle(int iPointerID)
void onLine(int iPointerID)
void onPen(int iPointerID)
void onEraser(int iPointerID)
void onNoTool(int iPointerID)
I primi tre metodi nella cornice sopra, sono quelli che vengono richiamati in caso di azione eseguita
nel programma di controllo SmartBoard. In caso infatti di selezione dei pulsanti dalla floating bar
(la barra non ancorata allo schermo facente parte del software di controllo della lavagna), che siano
il pulsante cerchio, rettangolo o linea, il listener riceverà la richiesta del metodo relativo (onCircle,
onRectangle, onLine) ed eseguirà il codice scritto in fase di implementazione del listener.
I tre metodi successivi invece, corrispondono alle funzioni richiamate automaticamente durante
l'uso fisico della lavagna (senza toccare quindi, il software di controllo Smart).
Per primo, troviamo onPen, il quale in seguito all'azione di rimozione di una penna dal pen tray (la
barra delle penne) viene eseguito per un dato iPointerID. Tramite questo iPointerID quindi, è
possibile, sfruttando la classe SBSDK descritta ad inizio sezione, ed i suoi metodi getToolColor,
getToolType e getToolWidth (Pag. 16), ottenere tutte le informazioni necessarie a capire quale penna
è stata utilizzata e cosa il nostro software deve fare a seguito di questo evento.
Analogamente, in caso di rimozione del cancellino dalla barra, la chiamata ad onEraser risulterà
automatica, e le possibili azioni e informazioni da ricavare tramite iPointerID sono le stesse. Va
ricordato però che il getToolType in questo caso restituirà un valore diverso da quello ottenuto per il
metodo onPen, poiché il cancellino appartiene ad una diversa tipologia di strumento rispetto alle
penne.
Infine, troviamo onNoTool, il quale, da come si può intuire dal nome, è il metodo conseguente
all'evento di posa di tutte le penne nella tray. Infatti, dopo aver posato tutti gli strumenti, il listener
avvierà questa funzione, per poter informare il nostro programma che ogni successiva azione è da
considerare come effettuata con il mouse o con un dito, o comunque con uno strumento che non
appartiene alla lavagna.
Gli altri metodi appartenenti alla classe SBSDKListener riguardano le azioni di pressione sulla
18
lavagna. Sono infatti rappresentati dalle varie funzioni che vengono avviate in caso di pressione,
dragging o rilascio di uno strumento sulla superficie sensibile al tocco.
Anche per questo gruppo di metodi, possiamo dividerli in due sottogruppi:
void onXYDown(int x, int y, int z, int iPointerID)
void onXYMove(int x, int y, int z, int iPointerID)
void onXYUp(int x, int y, int z, int iPointerID)
void onXYNonProjectedDown(int x, int y, int z, int iPointerID)
void onXYNonProjectedMove(int x, int y, int z, int iPointerID)
void onXYNonProjectedUp(int x, int y, int z, int iPointerID)
Il primo è rappresentato dalle funzioni che vengono chiamate nel caso in cui la lavagna stia
funzionando in modalità proiezione (quanto il proiettore è attivo). I tre metodi di questa
suddivisione, vengono quindi eseguiti al momento della rispettiva azione sulla lavagna nel caso in
cui il proiettore sia acceso.
onXYDown esegue il codice al suo interno al momento della sola pressione sulla lavagna di un
qualsiasi oggetto. Non importa infatti con cosa venga effettuata la pressione, poiché lo strumento è
ottenibile tramite uno dei parametri di funzione, iPointerID che grazie ai metodi della classe
SBSDK ci permette di ricavare le informazioni sull'oggetto utilizzato. Gli altri parametri del metodo
rappresentano la coordinata orizzontale (int x), quella verticale (int y) ed un altro valore che
rappresenta la quantità di pressione (int z) che non è però utilizzato nel caso di lavagne analogicoresistive.
Analogamente al metodo appena descritto, troviamo onXYMove, il quale, tramite gli stessi
parametri, esegue il codice al suo interno a seguito di un dragging con un oggetto sulla lavagna
( pressione e spostamento del cursore simultaneamente).
Il terzo metodo, onXYUp, da come si può intuire dal nome, viene richiamato al momento dello
spostamento dello strumento dalla superficie della lavagna.
Il secondo sottoinsieme di metodi, è caratterizzato da tre funzioni speculari a quelle appena
descritte, ma che vengono eseguite in caso di proiettore spento, e di uso quindi della lavagna come
semplice superficie sensibile al tocco.
I tre metodi si comportano esattamente come i corrispettivi per il caso di proiettore attivo;
onXYNonPojectedDown è associabile a onXYDown, onXYMove con onXYNonProjectedMove e
onXYUp con onXYNonProjectedUp.
19
Una particolare nota da segnalare a riguardo di queste funzioni e dell'action Listener per la lavagna,
riguarda il multitouch. Come detto in fase di descrizione della tecnologia analogico-resistiva
(Capitolo 2.1 ), questo tipo di lavagne non permette la cattura di più pressioni simultanee. In caso
infatti, di tale evento, i dati che si ottengono nelle varie funzioni di cattura dell'evento ( onXYDown
per esempio) non corrispondono ad entrambi i punti premuti o ad uno solo dei due, ma ad
un'interpolazione lineare tra le due posizioni.
Per fare più chiarezza su questo fatto, prendiamo in esempio due semplici punti:
P1(x,y) = (1,1)
P2(x,y) = (7,1)
In questo caso, le coordinate visualizzabili nel metodo onXYDown risulteranno:
P3(x,y) = (4,1)
Figura 3.1: Rappresentazione schematica dell'esempio descritto:
Nell'immagine sopra è disegnata una griglia rappresentate i possibili punti di
contatto, in maniera tale da rendere più comprensibile il concetto. In rosso il
primo punto di contatto, in blu il secondo. In verde vediamo la risultante calcolata
dalla lavagna tramite interpolazione dei punti 1 e 2.
Il valore cosi ottenuto quindi, non rappresenta alcun tipo di dato utile al nostro fine, poiché in base
alle informazioni all'interno del software, tale risultato può significare un singolo tocco in quel
punto, un tocco doppio (come nell'esempio di P1 e P2) oppure tocco multiplo (con interpolazione di
più di due punti). A seguito delle considerazioni appena fatte quindi, non si ha nessuna possibilità di
sfruttare il multitouch con gli strumenti a disposizione.
20
3.2 Considerazioni su User Interface
Dopo aver visto le caratteristiche delle API disponibili con la lavagna, si possono valutare i pro ed i
contro, ma soprattutto, è possibile capire cosa la nostra applicazione può fare, e quali eventi
possono essere catturati o gesti.
Come ampiamente scritto in precedenza, il multitouch non è sfruttabile, e questo ci limita
notevolmente nella scrittura di applicazioni ad alto tasso di interattività.
Considerando la conformazione e la grandezza della lavagna, bisogna fare attenzione a limitare al
massimo gli input dell'utente. La lavagna infatti, è uno strumento facile e veloce da utilizzare, a
patto però che le applicazioni che si usano siano studiate per appositamente per le LIM, o
richiedano il minimo sforzo da parte dell'utilizzatore.
Prendiamo in esempio il caso di una presentazione multimediale, dove gli input sono ridotti ai
minimi termini: cambio slide, inserimento di un commento o di una nota, avvio o terminazione
della presentazione. In questo caso non c'è bisogno di un'interfaccia grafica complessa o particolare,
poiché i comandi necessari al corretto svolgimento dell'azione sono pochi, e facilmente collocabili
all'interno di un programma (per le lavagne Smart Board esiste un plugin apposito per Powerpoint,
fornito assieme al software di controllo).
Se contrariamente invece, prendiamo il caso di un software di elaborazione fogli di calcolo (ad
esempio Excel), non è difficile immaginare le difficoltà dell'utente. Ogni volta che si vuole inserire
in una cella un qualsiasi carattere alfanumerico, è necessario premere il pulsante nella tray bar
corrispondente alla tastiera, attendere la comparsa della tastiera a schermo, premere con un dito o
uno strumento i caratteri da inserire e quindi tornare al nostro software di fogli di calcolo. Il
procedimento è molto macchinoso da effettuare, soprattutto se le celle da compilare sono in numero
elevato.
In alternativa, è possibile utilizzare un programma apposito della lavagna che riconosce la scrittura
manuale, ma come per la tastiera a schermo, è necessario attivare la finestra, spostarci su di essa,
scrivere manualmente il carattere e verificare che il programma lo abbia riconosciuto correttamente,
ed in caso contrario si dovrà eliminare il carattere appena inserito, e riprovare a scriverlo. Il tool
sarebbe quindi un'ottima alternativa all'uso della tastiera, se solo fosse più comodo e veloce da
attivare, e se riconoscesse perfettamente i caratteri immessi (sarebbe sufficiente una fase di
apprendimento della propria scrittura). Come ultima soluzione al problema di cui sopra, rimane
sempre la possibilità di utilizzare la normale tastiera connessa al PC, tenendo conto però del fatto
che non si troverà mai attaccata alla lavagna, ed in alcuni casi non è situata in posizioni semplici da
raggiungere con frequenza.
Altro esempio utile a sottolineare questo problema è la navigazione internet, per la quale la lavagna
può essere un comodo strumento per mostrare a molte persone un determinato sito e navigarci
all'interno (i click si effettuano premendo proprio fisicamente i link), è dato dal fatto che
l'inserimento manuale dei link, come detto sopra, risulta troppo macchinoso. Inserire un link
utilizzando il riconoscimento della scrittura è troppo complesso, le probabilità di riconoscimento
errato degli input è molto alta. L'inserimento tramite tastiera a schermo invece è più semplice, ma è
un procedimento lento e frustrante, si pensi ad un qualsiasi sito con indirizzo esteso o con caratteri
particolari, per inserirlo completamente si spreca troppo tempo inutilmente.
21
Come abbiamo visto quindi, ogni applicazione che contiene sezioni relative all'immissione di campi
di testo, risulta troppo difficoltosa nell'ambito delle lavagne multimediali.
Il concetto di multimedialità infatti, per quanto riguarda le LIM, è limitato all'uso di pennarelli,
mouse o facendo pressione con le dita, e di conseguenza, l'interfaccia utilizzata in questo ambito
deve essere semplice da vedere e da utilizzare, possibilmente con pulsanti, e menù contestuali. In
aggiunta, è necessario evitare una grafica troppo complessa, che potrebbe essere una limitazione
all'utilizzo, infatti, una LIM ha dimensioni superiori ad uno schermo di un PC e quindi, l'utente che
la utilizza non ha la visione ampia come su un normale monitor. Si può quindi giungere alla
conclusione che l'interfaccia deve presentare gli oggetti indispensabili alle funzioni primarie
dell'applicazione, con la possibilità di mostrare con semplicità anche gli strumenti secondari ( ma
solo in seguito ad una richiesta esplicita in fase di uso del programma), rendendo così più veloci le
operazioni più comuni, essendo quindi, la user-interface, minimale e funzionale, evitando gli
elementi ridondanti o di scarso utilizzo.
3.3 Possibili soluzioni
Le considerazioni fatte fino ad ora sono servite come materiale di studio riguardante una possibile
interfaccia semplice e pulita, che si adatti possibilmente ad ogni tipo di software che sfrutta le
lavagne interattive multimediali. Il metodo di interfacciamento da sviluppare deve inoltre, garantire
a chi utilizza la lavagna di poter apprendere velocemente il funzionamento del programma stesso, e
di fare in modo che ogni componente sia facile da trovare ed utilizzare. Ne sono derivate quindi tre
possibili soluzioni candidate al nostro fine. La prima soluzione proposta, è rappresentata
dall'utilizzo di una toolbar come “menu di penna” (Capitolo 3.3.1), lo sfruttamento di un motore in
grado di riconoscere la scrittura manuale dell'utente (Capitolo 3.3.2), e la gestione delle azioni
tramite interpretazione di gesture con gli strumenti a disposizione (Capitolo 3.3.3).
Vengono in seguito analizzate le tre soluzioni in maniera più approfondita, mostrando pregi, difetti e
dove possibile, esempi concreti del loro utilizzo.
3.3.1 -
Il “menu di penna”
L'idea del menù di penna inizialmente può sembrare fin troppo banale; si tratta di una semplicissima
menù bar generata tramite la libreria Swing di Java, contenente un gruppo di elementi per ogni
colore di penna a disposizione della lavagna (più un menù per il cancellino). Nonostante quindi
l'idea di base molto semplice, questa tecnica permette di avere sotto mano uno strumento completo
e facile da utilizzare. Il punto di forza principale è sicuramente rappresentato dalla posizione e dalla
conformazione del menù. La toolbar si trova infatti nella parte bassa dello schermo, poco sopra il
vassoio su cui le penne sono appoggiate.
Ogni penna (cancellino compreso) ha un menù ad essa corrispondente, che è situato in posizione
relativa allo strumento (ad esempio vicino alla posizione della penna nera sul vassoio, vi è il menù
corrispondente alle funzioni per lo strumento nero) ed è caratterizzato da un colore di sfondo uguale
a quello della penna associata. La posizione, le dimensioni contenute ed i pochi bottoni presenti,
22
rappresentano quindi risposte positive alle richieste presentate in precedenza, rendendo quindi la
soluzione valida. Il passo successivo, è sicuramente quello di verificare la fattibilità della toolbar in
questione con il linguaggio Java.
La flessibilità del linguaggio di programmazione da noi scelto, ci permette per l'appunto di poter
creare e posizionare il menù nella posizione per esso migliore. E' possibile inoltre creare menù
separati per ogni penna e dividerli con dello spazio libero, così da rendere più pulita l'interfaccia.
Un altrettanto utile elemento a disposizione è dato dalla possibilità di associare ad ogni elemento
del menù una icona caratteristica per quella funzione. Infine segnaliamo anche la presenza di
sottomenù utili a dividere in categorie le varie azioni da assegnare alle penne.
Figura 3.2: La toolbar è formata da cinque menù differenziati per colore, ognuno della
stessa rappresentazione cromatica della penna corrispondente. Ogni menù è reso
isolato dagli altri tramite dello spazio libero, così da rendere più intuitivo l'uso della
toolbar.
Se vogliamo alcuni esempi di azioni attuabili con questa toolbar, è sufficiente pensare all'esempio
descritto nella sezione precedente, riguardante la scrittura di testo; tramite l'utilizzo del “menù di
penna” possiamo associare ad ogni penna una determinata parola (inserendo quelle di uso più
comune, o dando all'utente la possibilità di specificare la parola da impostare per la penna) e fare in
modo che ogni volta che si clicca con quello strumento, la parola venga automaticamente inserita.
In alternativa, si possono sfruttare le azioni personalizzabili per assegnare ad una determinata penna
la simulazione della pressione di determinati tasti, o di combinazioni di essi, come ad esempio la
pressione del tasto destro del mouse (tale pulsante è presente sulla lavagna, ma per sfruttarlo è
necessaria una sequenza di operazioni molto macchinosa).
Ne deriva da quanto detto, che la soluzione proposta è valida e realizzabile concretamente, e verrà
quindi tenuta in considerazione nella scelta per la realizzazione dell'interfaccia.
3.3.2 -
Handwriting Recognition
Un'altra valida risposta alla semplificazione dell'interfaccia è rappresentata dall'utilizzo di un
Handwriting Recognition. Tale tecnica altro non è che una scansione OCR su di un'immagine in cui
l'utente ha scritto a mano del testo. Il funzionamento è di per se semplice, poiché è sufficiente creare
una zona “sensibile” in cui l'utente scrive del testo. Questo testo verrà poi preso in input e
riconosciuto, trasformando in stringa l'immagine presa in oggetto. Data la stringa quindi, è facile
immaginare e decidere, dal lato del programmatore, cosa il software deve fare (inserire quel testo in
un campo, piuttosto che cercare un'azione corrispondente al testo inserito).
L'idea di base sembra ottima, ma ci sono delle limitazioni; nonostante i molti tentativi fatti, ed i vari
23
programmi presenti nel web, non è stato possibile trovare una soluzione soddisfacente.
Cercando informazioni a riguardo, ci siamo imbattuti in un discorso interessante da parte di una
sviluppatrice Java (Dana Nourie [9]) che aveva iniziato il progetto di un HWOCR (Handwriting
OCR) per la tecnologia Java, ma, di aver dovuto abbandonare il progetto, poiché la tecnologia Java
non permetteva un corretto riconoscimento dell'immagine da processare. L'idea di base di tale
progetto si basava sul modello di Markov ( [10] ) e l'algoritmo di Viterbi ( [11] ).[12] In aggiunta a
questo problema, va considerato anche il fatto che, nei dispositivi in cui HWOCR è funzionante,
viene imposto all'utente di scrivere i caratteri secondo un certo schema logico e seguendo
determinate dimensioni.
Queste restrizioni, nel nostro caso non potrebbero essere attuate, poiché se l'interfaccia presentasse
tutte queste limitazioni, si uscirebbe dai canoni di semplicità e duttilità descritti in precedenza. Ai
problemi appena incontrati, è però possibile ovviare, con due eventuali casi:
Il primo è rappresentato dall'opportunità di inviare ad un programma esterno l'immagine riportante
la scrittura manuale. Tale pratica renderebbe le cose semplici poiché il programma esterno, data
un'immagine in input, restituisce la stringa corrispondente al nostro software. In realtà però questo
meccanismo non è cosi semplice, dal momento che non è stato trovato alcun programma che riceve
in input un'immagine. Tutte le proposte trovate infatti, non accettano input se non quello in tempo
reale del mouse, e questo fatto, come ampiamente detto fin'ora non è tollerabile ai fini di un
software che segue le richieste ipotizzate.
La seconda soluzione è rappresentata dal HWOCR integrato nel software della tastiera. Questo
semplice riconoscitore è uguale a quello che si può trovare in un palmare; presenta un campo in cui
inserire il testo a mano, il quale verrà poi trasformato in stringa ed inserito nell'ultima posizione in
cui era situato il mouse. La precisione nel riconoscere la scrittura, dopo alcuni tentativi, è risultata
piuttosto buona, tuttavia la lentezza nel ricevere l'input e dare l'output, e la macchinosità della
finestra (per visualizzarla è necessario aprire la tastiera a schermo e quindi selezionare la voce
relativa al riconoscimento della scrittura) rendono l'alternativa inaccettabile.
Abbiamo quindi visionato anche questa alternativa, reputandola valida per quanto riguarda l'ipotesi,
considerandola improponibile per la sua fattibilità, ma soprattutto troppo macchinosa per poter
soddisfare il requisito di user-interface minimale e veloce da utilizzare.
3.3.3 -
Controllo tramite Gestures
La terza soluzione proposta per lo sviluppo dell'interfaccia è basata sul riconoscimento di gestures,
predefinite o personalizzabili, per specificare l'azione da eseguire.
Questa tecnica sfrutta, in maniera simile all'HandWriting Character Recognition, un pannello
dell'interfaccia grafica sensibile ai movimenti ( che può essere specifico o l'interfaccia per tutta la
sua estensione) di click, dragging e pressione degli strumenti sulla lavagna. Definendo
preventivamente delle gesture standard è possibile differenziare ogni azione da svolgere e
classificarla in base al movimento richiesto. Per poter abilitare una penna ad una determinata
azione, è sufficiente svolgere la gesture ad essa associata nella zona sensibile. Il software si incarica
di leggere i movimenti fatti dall'utente e di interpretarli come comandi.
24
L'idea di base è intuitiva e sembrerebbe, tra quelle proposte, la più “user-friendly”. La tecnica in
questione però presenta anche alcuni problemi, primo tra tutti il fatto che l'utente debba imparare o
impostare le gestures e, sebbene la personalizzazione sia semplice, l'apprendimento rappresenta un
ostacolo. Se ogni utente infatti, dovesse imparare più di tre o quattro gesture, il tempo di
apprendimento crescerebbe notevolmente, riducendo la semplicità di utilizzo. Tuttavia superata la
fase di studio delle gesture, l'esecuzione risulta veloce e scorrevole.
Analizzando quindi meglio i metodi per poter sviluppare tale interfaccia, incappiamo nuovamente
nella necessità di riconoscere ed interpretare forme specifiche, rimandandoci al problema del
riconoscimento della scrittura a mano, che, come detto in precedenza non è nel nostro caso una
soluzione attuabile.
25
26
Capitolo 4: Fisica 2D
Con l'aumentare della potenza di calcolo delle CPU è cresciuto anche il desiderio di sfruttare
pienamente tali processori. Tralasciando i vari programmi di benchmarking, l'alternativa allo
sfruttamento della sempre maggior frequenza delle unità di elaborazione è data dall'utilizzo di
programmi di simulazione fisica. La categoria è estremamente ampia, basti pensare ai motori fisici
nei videogiochi, a quelli utilizzati per il testing delle autovetture da competizione o dalla
riproduzione del volo di un aeroplano, ma nel nostro caso ci limiteremo alla riproduzione di un
ambiente di fisica bidimensionale.
Per avere un'idea reale di questa situazione pensiamo al gioco del biliardo. Ogni movimento è
eseguito seguendo due assi cartesiani (tralasciando i tiri impropri del gioco in cui la pallina si
solleva dalla superficie del tavolo ) ed ogni contatto tra due o più elementi è elastico, cioè nessun
componente modifica la sua forma, gli oggetti mobili (le palle) reagiscono ad ogni contatto subendo
una forza ed un'accelerazione muovendosi, mentre gli oggetti che chiamiamo impropriamente
“fissi” (le sponde del tavolo) subisco e restituiscono forze, ma non presentano alcun movimento.
Per rappresentare quindi l'ambiente appena descritto, sarà necessario un motore fisico in grado di
simulare azioni e reazioni in base a valori fisici decisi a priori (come massa, densità, attrito) e di
estrapolare tutte le informazioni, rappresentandole sotto forma di dati (valori interi, stringhe di
caratteri, valori booleani) che verranno poi valutati ed utilizzati da un motore grafico apposito. Il
motore fisico che si vuole utilizzare, deve essere però il più preciso possibile, poiché, anche un
semplice errore può significare una simulazione totalmente discostata dalla realtà. Per esempio
possiamo pensare al momento della collisione tra una palla ed una sponda del tavolo da biliardo, in
questo caso un piccolo errore di calcolo delle forze in gioco, può consegnare al motore grafico dei
dati molto diversi da quelli attesi, con conseguente risultato di vedere magari, la pallina che tocca
perpendicolarmente una sponda ed invece che tenere la stessa direzione con verso opposto, cambia
direzione, rimbalzando in maniera inaspettata.
Riguardo la precisione dei simulatori di fisica, va precisato che quest'ultimi si dividono in due
categorie; ad alta precisione o real-time.
Nel primo gruppo troviamo i motori utili a calcoli precisi ed estremamente fedeli alla realtà, come
nel caso della simulazione del comportamento dei pneumatici. Per poter avere dei dati precisi che
27
rispecchino le vere caratteristiche della gomma, è necessario testare le possibili soluzioni
utilizzando un motore fisico che simuli esattamente una situazione reale. Questo motore fisico per
poter essere preciso deve necessariamente fare uso di algoritmi complessi, con un conseguente
carico elevato per il processore. Al fine di poter ottenere i dati in un tempo accettabile il simulatore
compie tutti i calcoli prima di mostrare i risultati, con la conseguenza di non poter modificare i dati
in fase di visualizzazione della simulazione, ma solo di modificarli ed effettuare una nuova
situazione. Questo accorgimento permette al software di sfruttare tutta la potenza elaborativa sulle
proprietà degli oggetti da simulare, evitando quindi l'utilizzo di cicli macchina nella verifica e nel
calcolo degli input dati dall'utente.
In opposizione ai motori fisici ad alta precisione, troviamo quelli real-time che permettono all'utente
di modificare l'ambiente, le proprietà degli oggetti (massa, posizione, direzione, verso) e di
aggiungerne di nuovi o eliminare quelli presenti. Ne deriva quindi che i calcoli alla base del motore
saranno semplificati, in modo da permettere al software di rispondere in tempo reale agli input
dell'utente e di calcolare ad ogni istante i parametri fisici caratteristici degli oggetti. Di norma, i
motori fisici real-time, calcolano le proprietà fisiche degli oggetti in movimento, mentre per quelli
che stanno in una situazione di inerzia rispetto all'ambiente, le rispettive proprietà vengono bloccate
fino al momento in cui l'oggetto non viene mosso da un input dell'utente o dal contatto con un altro
oggetto, risultando così per quel lasso di tempo, oggetti statici.
Il riconoscimento delle collisioni all'interno del sistema viene effettuato dal motore fisico per mezzo
di un algoritmo apposito. Non vi sono particolari specifiche riguardo l'algoritmo da utilizzare, ma
può sfruttare due tecniche diverse, che sono il calcolo della collisione a priori (prima del contatto)
o a posteriori (dopo il contatto).
Sfruttando il calcolo a priori, l'algoritmo utilizzato deve essere basato sul tempo, e deve prevedere
esattamente la velocità, la traiettoria ed i movimenti degli oggetti nel sistema. Grazie a queste
previsioni, i contatti tra gli oggetti vengono calcolati con una precisione molto alta, evitando che i
corpi si sovrappongano nella stessa posizione. Questo metodo viene chiamato a priori perché la
collisione tra gli oggetti è calcolata nell'istante prima di aggiornare la configurazione dei corpi in
questione, anticipando il contatto. A vantaggio del calcolo a priori, troviamo una fedeltà maggiore
nei movimenti dei corpi ed una maggior stabilità nella visualizzazione grafica, poiché con il calcolo
anticipato, non ci si troverà mai ad avere due oggetti sovrapposti (situazione che non rispecchia la
realtà).
Il calcolo a posteriori invece sfrutta una tecnica totalmente differente, ma che semplifica di molto la
gestione della fisica. La simulazione grafica viene appositamente mostrata un'istante dopo quella
risultante dagli algoritmi implementati, quindi, ad ogni istante della simulazione, l'algoritmo che si
incarica di riconoscere le collisioni riceve in input tutti gli oggetti presenti nel sistema e si occupa di
verificare se ci sono contatti tra di essi. Questa tecnica è chiamata a posteriori poiché la collisione
viene riconosciuta solo dopo essere avvenuta, mancando di fatto il momento del contatto. A favore
di questo metodo però, troviamo sicuramente la maggior semplicità nello scrivere l'algoritmo di
cattura delle collisioni e una maggior velocità nell'eseguirlo. Non c'è infatti il bisogno di prendere in
considerazione tutte le possibili variabili che interferiscono con il sistema ed i suoi componenti, ed
in caso di una quantità elevata di oggetti, l'algoritmo dovrà soltanto prendere in input una lista di
tali elementi, e verificarne la possibile sovrapposizione, senza curarsi di tutte le proprietà fisiche in
gioco.[13]
28
4.1 Pacchetti di fisica 2D disponibili
Come abbiamo visto, i motori fisici possono essere definiti attraverso alcune semplici suddivisioni
in base al loro fine ed alle tecniche sfruttate per il funzionamento. Considerando il nostro interesse
nello sviluppare un'interfaccia utente per un software multimediale che fa uso delle lavagne
interattive, sicuramente possiamo indirizzarci verso un motore fisico real-time, il quale permette
all'utente di interagire attivamente e di modificare il sistema in azione.
Di seguito quindi, passeremo ad analizzare alcuni dei pacchetti di fisica a disposizione. Per brevità
non li potremo elencare tutti, sia per la vastità di proposte, sia per la difficoltà nel reperire
informazioni a riguardo di alcuni di loro.
Tra le varie soluzioni che non abbiamo proposto, segnaliamo Farseer Physics Engine e
Physics2D.Net per quanto riguarda i pacchetti open source, mentre per quelli a livello commerciale
Havok e PhysiX, i quali sono due motori fisici molto famosi e ampiamente utilizzati nel ramo dei
videogame (in questo caso la fisica è spesso tridimensionale).
Oltre a quelli appena citati ce ne sarebbero molti altri, tra i quali ne abbiamo selezionati cinque, per
valutarli come possibili motori per la nostra applicazione interattiva.
4.1.1 -
Box2D
Box2D è una libreria open source che contiene un motore fisico a due dimensioni. I corpi simulati
tramite Box2D sono solidi, cioè non hanno la caratteristica di modificare la propria forma in base
agli impulsi ( non possono quindi deformarsi ). Il movimento degli oggetti viene effettuato grazie ad
algoritmi che calcolano posizione, velocità e direzione in base soprattutto a tre parametri
caratteristici del corpo, che sono densità, elasticità e attrito.
Il contatto tra gli oggetti è garantito tramite un algoritmo che viene eseguito in real time e
semplificando inizialmente gli oggetti secondo una schema AABB ( ogni oggetto è compreso in un
quadrato ). In tal modo, ogni volta che due quadrati AABB vengono a contatto, il motore verificherà
un'eventuale collisione tra i relativi elementi del sistema. Il funzionamento e l'utilizzo del motore
sono semplificati e veloci; dopo aver creato il “mondo” (per noi il sistema) si procederà a definire
delle “forme” (shapes) indicanti il tipo di oggetto da creare, attribuendolo di seguito all'insieme
degli elementi del sistema, assegnandogli una massa e, se necessario, unendolo ad altri oggetti
(creando cosi nuove forme date dalla composizione di forme base).
Completati i passi di creazione, è sufficiente avviare la simulazione per poterla testare e poter
muovere gli oggetti. La libreria contiene svariate funzioni per molte azioni, riducendo i limiti
riguardo a ciò che si può creare nel sistema.
A tale proposito, oltre ad indicare la possibilità dell'unione degli elementi e la cancellazione di
quelli già creati, Box2D permette il posizionamento di oggetti statici nell'ambiente, rendendo
possibile la simulazione del terreno o lasciandoci creare uno schema predefinito (come può essere
una discesa con conseguente salita). In aggiunta a tutto ciò, vi è un elemento di grande spicco reso
disponibile dal motore fisico. Questo elemento, chiamato sensore, è uno “strato di ambiente”
29
invisibile che, lancia un'eccezione se qualche oggetto entra nei suoi limiti. L'eccezione, se catturata,
può permettere all'utente di eseguire una determinata azione.
Questa peculiarità di Box2D, realizzato in C++ da Erin Catto, ha posto le basi per un videogioco
commerciale, Crayon Physics Deluxe (Sviluppato da Petri Purho)[14], il quale grazie a questo
motore fisico ed all'idea innovativa ha lasciato profondamente il segno, vincendo un premio
all'Independent Game Festival. Il gioco mostra al giocatore un mondo caratterizzato da una palla
(oggetto da muovere), una serie di ostacoli (da evitare per arrivare alla soluzione) ed una bandiera,
che rappresenta graficamente il sensore sopra descritto.
Figura 4.1: Crayon Physics: Una schermata del gioco. La stella gialla
rappresenta la meta, da raggiungere con la palla rossa. La palla non è
controllata direttamente dall'utente ma solo tramite la creazione e lo
spostamento di oggetti supplementari, come in questo caso la barra blu ed i
quadrati verde e rosso (è stata creata una leva per far muovere la palla).
Tramite l'uso del mouse l'utente deve disegnare degli oggetti che serviranno a portare la palla alla
bandiera. Il grande successo di questa versione in C++, ha reso possibile la nascita di svariati
porting in altri linguaggi di programmazione come Flash, Phyton, JavaScript, Nintendo DS e, come
vedremo nella prossima sezione, Java.
30
4.1.2 -
JBox2D
JBox2D è, come accennato poco sopra, una trasposizione da C++ a Java di Box2D.
Le caratteristiche e le funzionalità rimangono pressoché invariate, fatta eccezione per alcuni piccole
mancanze. Tra tutte spicca il supporto non completo ai sensori, quest'ultimi infatti sono stati da
poco implementati e presentano ancora numerosi problemi, risultando quindi inutilizzabili ai nostri
fini. Ad ogni modo, fatta eccezione per questa mancanza tutte le principali e più comuni
caratteristiche di Box2D sono presenti anche in questo porting, per esempio la funzione di
“sleeping” per gli oggetti non in movimento.
La tecnica appena descritta fa si che, se un elemento non è in fase di movimento, trovandosi quindi
in una situazione di inerzia rispetto al sistema, tale elemento viene escluso dalla simulazione realtime, diminuendo cosi i calcoli ed i controlli che il software deve eseguire, riducendo di
conseguenza il consumo di risorse.
Va sicuramente segnalata la feature in programma da parte degli sviluppatori, che permette la
serializzazione del mondo e degli oggetti in esso, dando quindi all'utente la possibilità di salvare e
continuare in futuro la simulazione. JBox2D è in continuo sviluppo, è presente un gruppo di
discussione ed un server SVN ad esso dedicati.
4.1.3 -
Phun
Il motore fisico Phun è, da come è stato definito dal suo creatore: “un gioco freeware classificato
come sandbox ( un gioco cioè che non ha un fine preciso) dove è possibile sfruttare la fisica come
mai in precedenza”. La frase definisce effettivamente ciò che Phun rappresenta, infatti tramite
questo motore fisico è possibile disegnare qualsiasi cosa, senza limitazioni (disegno a mano libera),
animando quindi ogni oggetto creato.
Phun è quindi un'applicazione che ci permette di sfruttare interattivamente il motore fisico. A
differenza di Box2D (Paragrafo 4.1.1) infatti, con Phun è possibile disegnare liberamente gli
elementi che agiranno nell'ambiente simulato.
Il simulatore supporta i corpi rigidi (non permette quindi cambi di forma degli stessi), contatti,
attriti, molle, motori ed una particolare simulazione riguardante i movimenti dei fluidi. E' possibile
inoltre specificare per ogni elemento un colore di riempimento, con in aggiunta l'eventuale modifica
dei parametri caratteristici degli elementi, come attrito, coefficiente di rimbalzo, e velocità per i
motori.
31
Figura 4.2: Immagini di Phun.
Nelle due figure possiamo vedere il motore fisico in azione. A sinistra una esempio in cui
una palla si scontra con un muro di mattoni, a destra la finestra per la personalizzazione dei
motori.
Phun sfrutta un motore fisico interno, sviluppato inizialmente da Emil Ernerfeldt (Umea University,
Svezia) come tesi di laurea magistrale e perfezionato in seguito dall'azienda Algoryx[15]. A seguito
del passaggio a tale azienda, il programma, pur rimanendo freeware per uso non commerciale, è
diventato closed-source e quindi, non è possibile utilizzarlo per la nostra applicazione interattiva a
causa dell'impossibilità di interfacciare il nostro software con Phun.
4.1.4 -
Tokamak
La successiva libreria di fisica simulata è rappresentata da Tokamak. Questo motore fisico open
source e sviluppato in C++, è studiato e creato appositamente per simulare la fisica nei videogiochi
e sfrutta le librerie Direct X di Microsoft Windows. Il suo funzionamento è caratterizzato da un alto
tasso di velocità e precisione.
In Figura 4.3 possiamo vedere una schermata durante una simulazione di corpi composti, lasciati
cadere liberamente su di una scalinata.
32
Figura 4.3: Caduta di oggetti in Tokamak.
In questo esempio possiamo vedere degli oggetti (a forma di persone) che
cadono liberamente su degli scalini. Si può vedere la tridimensionalità
dell'ambiente.
Gli algoritmi di calcolo delle collisioni e del movimento degli oggetti infatti, utilizzano un metodo
iterativo molto complesso, che permette agli sviluppatori di avere a disposizione una simulazione
precisa e veloce. Questa velocità elevata è garantita appunto dall'algoritmo implementato, il quale
non fa uso di pesanti e grosse matrici di dati, evitando allo stesso tempo il problema dell'uso
eccessivo di memoria. Grazie a questo accorgimento infatti, Tokamak ha la peculiarità di essere un
buon candidato nei casi in cui gli oggetti da muovere e gestire siano piuttosto elevati. Come per le
altre librerie viste fin'ora, anche in Tokamak è possibile unire più oggetti tra loro (tramite apposite
funzioni di Joint). Da segnalare di particolare, c'è il sistema di riconoscimento dei contatti tra gli
oggetti che, oltre ad essere molto efficiente, permette la cattura di collisioni tra forme base ( cubi,
sfere e cilindri ) ma anche tra combinazioni di esse ( unioni o joints ), e tra oggetti convessi,
riconoscendo con esattezza la parte di elemento che sporge dalla forma base. Una caratteristica
particolare non ancora vista nei motori fisici precedenti, è la presenza dei cosiddetti Breakage i
quali, dopo essere stati creati, in caso di collisione con un altro oggetto, vengono scomposti in
frammenti ( dividendo l'elemento in parti primitive) che seguono traiettorie automaticamente
calcolate in base alla collisione.
Per quanto riguarda il nostro fine la libreria non è però utilizzabile perché lavora in un ambiente
tridimensionale, il quale risulta troppo complesso per essere gestito ed utilizzato interattivamente
tramite una semplice lavagna interattiva multimediale, soprattutto dopo aver verificato
l'impossibilità di utilizzare il tocco multiplo sulla lavagna stessa.
33
4.1.5 -
Phyz
L'ultima libreria che andiamo ad analizzare è Phyz, un motore fisico bidimensionale sviluppato per
ambiente Windows. Questa restrizione è data dal fatto che il programma fa uso delle librerie di
sistema Microsoft DirectX (versione 9) per accelerare la rappresentazione grafica e per poter offrire
all'utente suoni che rappresentano la situazione in corso. L'obbiettivo primario è quello di simulare
alcuni fenomeni fisici e modellare a proprio piacimento un ambiente fisico e per questo motivo, non
è permessa all'utente la modifica dei dati caratteristici degli oggetti (come attrito, peso e coefficiente
di rimbalzo). Nonostante questi impedimenti, il motore permette la modellazione di una grande
quantità di oggetti senza soffrire di rallentamenti dovuti ai troppi calcoli, sia grazie agli algoritmi
implementati, sia in seguito all'adozione di un principio basato su particelle (ogni oggetto è formato
dall'unione di più particelle, ad esempio una scatola non ha delle linee diritte, ma più particelle
collegate tra loro). Tramite l'utilizzo di questo sistema a particelle inoltre, Phyz implementa la
simulazione dinamica dei corpi, dando cosi la possibilità di modificare la loro forma, di romperli o
di unirli.
Figura 4.4: Immagine rappresentativa di Phyz.
Nella figura vediamo una schermata del simulatore. A sinistra una visione
dell'insieme del motore, in primo piano sulla destra invece, le “particelle” su cui il
motore si basa.
Come detto inizialmente però, Phyz è sviluppato in ambiente Windows, facendo uso di DirectX e,
fattore non di poca importanza è si libero per l'uso, ma non è open source. Sebbene tramite
un'applicazione esterna, presente assieme al motore fisico, permetta la gestione ed il controllo degli
eventi, non è possibile nel nostro caso farne uso, poiché quest'applicazione, chiamata PhyzLizp è
basata sul linguaggio di programmazione Lisp, il quale non è presente tra i linguaggi abilitati
all'interfacciamento con il software e la lavagna SmartBoard.
34
4.2 Analisi delle librerie
Dopo aver analizzato alcuni dei molti pacchetti disponibili ci troviamo a dover trarre delle
conclusioni riguardo a quali di questi possono risultare utili al nostro fine, cercando anche di
valutare le motivazioni per quelli che invece non rappresentano una valida proposta.
Tra tutte le considerazioni che possono influire sulla scelta del motore fisico, la prima in assoluto è
quella che riguarda il codice sorgente. Il nostro simulatore di fisica, per poter essere utilizzato in
abbinamento alla lavagna, deve darci la possibilità di collegarlo alla nostra interfaccia. Nel caso in
cui si scelga quindi una libreria non open source, bisogna avere la possibilità di richiamare le
funzioni interne al motore fisico direttamente dalla nostra interfaccia. Questa operazione non è però
possibile nella quasi totalità delle librerie closed source, poiché non abbiamo questa disponibilità e
l'unico modo di utilizzare il simulatore è tramite il mouse, fatto che renderebbe inutile la nostra user
interface creata.
Analizzando quindi i pacchetti con sorgenti liberi, ci troviamo a dover considerare l'ambiente in cui
il software verrà sviluppato. Alcuni motori fisici sono stati implementati appositamente in un dato
linguaggio o tramite un'architettura specifica. Per fare un esempio, il simulatore Tokamak,
sviluppato in C++ e scritto specialmente per Microsoft Windows, restringe l'ambito di utilizzo al
solo sistema operativo sopra elencato. E' tuttavia possibile modificare il codice per farlo funzionare
su un altro sistema operativo come ad esempio un sistema Unix, ma questo comporterebbe una
verifica e modifica totale del codice. Dalle considerazioni fin qui fatte, ne deriva che la libreria
candidata all'utilizzo nel nostro software, dovrebbe teoricamente essere libera da vincoli dati dal
sistema operativo.
Oltre all'analisi prettamente informatica, per valutare il motore fisico più affine alle nostre necessità,
dobbiamo considerare anche il fattore puramente fisico della libreria, ed il suo impatto interattivo se
applicato ad una periferica di input come la lavagna interattiva multimediale.
Per quel che riguarda il fattore fisico, le caratteristiche del simulatore devono essere si ampie, ma
non troppo complesse o macchinose. A questo scopo un motore fisico pesante ed elaborato, che
valuta esattamente ogni minimo aspetto della fisica reale (tridimensionalità, effetto del vento,
oggetti deformabili), creerebbe già al primo utilizzo delle perplessità da parte della persona che lo
utilizza. Poniamo l'esempio dell'ultima libreria visualizzata (Phyz) che è, come visto in precedenza,
un simulatore fisico caratterizzato da un'interfaccia grafica poco intuitiva e troppo vincolata ad uno
schema standard. Ogni elemento che si vuole creare o modificare deve essere posizionato con
precisione, e l'utilizzo di questo simulatore è poco intuivo considerando anche il fatto che, dopo
aver posizionato un elemento, per esempio una molla, non è possibile cambiare le sue caratteristiche
fisiche (nel nostro caso la costante elastica). Questo approccio semplifica da una parte l'uso, ma
riduce l'interattività dell'utente e vincola la simulazione ad una rappresentazione grafica che ha poco
a che fare con la realtà.
Prendendo in esame la libreria Box2D invece ci troviamo davanti ad un motore fisico totalmente
open source, abbiamo assieme ad esso una documentazione completa sulle caratteristiche, sulle
funzioni e sul metodo da seguire per sfruttare la fisica simulata. A differenza infatti delle altre
librerie, Box2D (e il corrispettivo Java JBox2D) è di fatto un motore fisico non vincolato ad uno
specifico codice per il disegno degli oggetti e dell'ambiente. Le funzioni infatti sono fatte per
restituire dati generici, lasciando a chi implementa la parte grafica, la scelta del metodo di
35
rappresentazione degli elementi. Questo fatto semplifica, soprattutto nel nostro caso, lo sviluppo di
un'applicazione grafica specifica per l'uso che vogliamo fare. Difatti, per sviluppare un simulatore
di fisica applicato al contesto delle LIM, dobbiamo innanzitutto avere la piena libertà di modificare
e personalizzare il codice di controllo degli input dell'utente, quindi adottare dei metodi appositi per
rispondere correttamente agli input ricevuti, ed in seguito rappresentare il tutto tramite una finestra
pulita e sgombra da oggetti ridondanti. Tutto questo ci è permesso con il motore fisico analizzato
inizialmente. In seguito però alle decisioni prese nei capitoli precedenti però, abbiamo deciso di
utilizzare la libreria JBox2D, la quale essendo un porting di Box2D, comprende le stesse
caratteristiche, ma aggiunge la flessibilità del linguaggio creato da Sun Microsystem, permettendoci
di scrivere un software adatto a più di una specifica architettura. Inoltre, utilizzando JBox2D e
sfruttando le API SmartBoard viste nel Capitolo 3.1, possiamo interfacciare in maniera veloce il
motore fisico e la nostra user interface appositamente studiata per l'uso con le lavagne interattive
multimediali.
36
Capitolo 5: Descrizione dell'architettura
Dopo aver analizzato gli strumenti ed i mezzi a nostra disposizione per la creazione del programma
oggetto di questa tesi possiamo passare alla scrittura del codice sorgente.
Il primo e più importante passo da fare è quello di creare l'interfaccia collegabile alla lavagna,
facendo in modo che tale interfaccia sia il più possibile flessibile ed adattabile ad ogni eventuale
programma da sviluppare appositamente per la lavagna. Facendo ciò ci ritroveremo con delle classi
Java indipendenti dal software che le utilizza, diventando quindi di fatto, una libreria stand alone.
Analizzeremo quindi la nostra soluzione mostrandone la flessibilità ed il suo funzionamento nel
caso proposto.
In seguito alla creazione di questo gruppo di classi vi sarà la necessità di connettere le azioni
selezionabili tramite interfaccia con gli eventi reali attuati dagli utenti. Tutto ciò viene fatto
sfruttando le API Java Smart Board viste nel Capitolo 3.1, le quali ci permettono di gestire tutti i
possibili eventi che possono verificarsi durante l'utilizzo da parte dell'utente. Mostreremo quindi la
tecnica adottata per effettuare il controllo degli input sulla lavagna, basandoci sulla soluzione da noi
implementata e mostrando come differenziare gli input da strumenti diversi.
Infine per completare i passi da compiere troviamo l'interfacciamento delle due parti principali del
software, la prima composta da menu grafico e sezione dedicata alla cattura degli eventi, la seconda
è rappresentata dal motore fisico. Analizzeremo in questo caso il procedimento da seguire per poter
ottenere una corrispondenza biunivoca tra input dell'utente e comportamento del simulatore di
fisica, facendo riferimento alla soluzione adottata, mostreremo la creazione degli oggetti a seguito
di un'azione eseguita sulla lavagna.
5.1 “Menu di penne” sviluppato
Come è stato ampiamente detto nei precedenti capitoli la migliore interfaccia utente per il caso delle
lavagne interattive multimediali è sicuramente quella che risulta più semplice da utilizzare, senza
però essere complessa o occupare troppe porzioni di schermo. La soluzione che abbiamo scelto di
implementare è quella riguardante il “menu di penne”. Tramite questa toolbar infatti possiamo
37
controllare pienamente tutti gli strumenti della lavagna semplicemente selezionando dalla barra
stessa il menù che descrive l'oggetto scelto. La posizione della barra potrebbe essere relativa alla
scelta dell'utente ma, per evitare confusione e per dare all'utente un punto di riferimento fisso, si è
deciso di bloccare il menù in una posizione statica, assegnandogli l'attributo di finestra in primo
piano. Tramite questo accorgimento, ogni azione eseguita all'interno del programma associato alla
toolbar, non influisce sulla visibilità della barra stessa, che continuerà ad essere un punto di
riferimento per l'interfaccia. La classe da creare dovrà quindi essere un'estensione di una classe base
per creare le finestre (JFrame), in modo da avere già a disposizione i metodi per la gestione delle
finestre stesse.
public ToolbarFrame(String s) {
super(s);
this.addWindowListener(this);
this.addComponentListener(this);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int hscreen = (int) screen.getHeight();
int wscreen = (int) screen.getWidth();
this.setSize(this.FRAMEW, this.FRAMEH);
int frameposx = (wscreen / 2) - (FRAMEW / 2);
int frameposy = (hscreen) - (FRAMEH * 3) / 2;
this.setLocation(frameposx, frameposy);
this.setResizable(false);
this.setUndecorated(true);
createToolBar();
position = this.getLocationOnScreen();
this.setVisible(true);
}
Codice 2: Il metodo riportato qui sopra è una parte del costruttore del menu
di penna.
Dopo aver assegnato alla toolbar i listener per il controllo della posizione, si passerà a
specificare la dimensione e la posizione sullo schermo. Infine si procederà con la
chiamata alla funzione dei menù interni, per poi rendere visibile la finestra.
Nel riquadro sopra, possiamo vedere il costruttore per il menù. Particolare attenzione va posta per
quello che riguarda il dimensionamento ed il posizionamento della barra. Dopo aver verificato la
risoluzione in uso con il metodo statico Toolkit.getDefaultToolkit().getScreenSize() sfruttiamo tale
dato per calcolare la posizione più adatta alla nostra toolbar. Questa posizione è idealmente nella
parte bassa dello schermo, centrando orizzontalmente la finestra. La posizione verticale invece, è
38
rapportata all'altezza della nostra barra. Nel nostro caso, il valore FRAMEH (altezza) del menù è di
21 pixel, la sua posizione in verticale è (3/2 *21) pixel sopra il limite basso dello schermo. Con
questo calcolo, otteniamo la posizione della barra che è esattamente quella voluta, centrandola
orizzontalmente rispetto allo schermo (avendo quindi la corrispondenza tra pentray della lavagna e
toolbar), e trovandola a fondo schermo ma con un piccolo spazio al di sotto di essa per ciò che
riguarda l'asse delle ordinate.
Altre due funzioni che meritano una particolare attenzione sono setResizable e setUndecorated. La
prima nega la possibilità di ridimensionare la finestra attraverso il mouse o la tastiera mentre la
seconda nasconde la cornice grafica classica dei frame, mostrando all'utente solamente il menù
stesso. Grazie a questi due metodi, otteniamo una soluzione a due dei problemi posti all'inizio cioè,
semplifichiamo l'uso della toolbar, limitando l'utente a svolgere le sole azioni per cui l'interfaccia è
studiata e rendiamo il nostro menù di penna pulito e snello, senza rappresentare graficamente quella
sezione di finestra che non si deve e può sfruttare e che rappresenterebbe solo un ostacolo alla
visione degli altri frame.
Il metodo che viene richiamato subito dopo, createToolbar, contiene il codice che può essere
considerato il cuore della toolbar, poiché è quello che compone i menù per ogni penna.
private void createToolBar() {
listener = new ToolBarListener(this);
menubar = new JMenuBar();
menubar.setOpaque(true);
menubar.setBackground(Color.WHITE);
black = new JMenuTool("Black Pen");
piblack = new PenToolsInfo(Color.BLACK);
black.setOpaque(true);
black.setBackground(Color.BLACK);
black.setForeground(Color.WHITE);
black.setMnemonic(KeyEvent.VK_B);
black.getAccessibleContext().setAccessibleDescription("Black Pen");
createMenu(black, ActionEvent.ALT_MASK, "Black");
menubar.add(black);
menubar.add(Box.createHorizontalGlue());
...
eraser = new JMenuTool("Eraser");
pieraser = new PenToolsInfo(Color.WHITE,"Eraser");
eraser.setOpaque(true);
eraser.setBackground(Color.WHITE);
39
eraser.setForeground(Color.BLACK);
eraser.setMnemonic(KeyEvent.VK_E);
eraser.getAccessibleContext().setAccessibleDescription("Eraser");
menubar.add(eraser);
menubar.add(Box.createHorizontalGlue());
this.setJMenuBar(menubar);
}
Codice 3: Metodo per la creazione dei menù per le penne.
In questo riquadro possiamo vedere il codice utilizzato per creare i vari menù per ogni
penna. Nell'esempio vediamo solo quelli per la penna nera e per il cancellino, poiché per
gli altri colori il procedimento è lo stesso.
Come vediamo nel riquadro sopra, dopo aver impostato un ToolbarListener (che vedremo in
seguito) si crea un oggetto JMenuBar appartenente alle classi swing di Java. Questo oggetto
rappresenta il menù di penne che viene visualizzato in condizione di idle dell'interfaccia. Abbiamo
deciso di colorare questa nostra toolbar di bianco, e per poterlo fare è necessario applicare l'attributo
setOpaque, altrimenti i metodi di colorazione verrebbero ignorati, e quindi assegnare il colore alla
barra tramite setBackground, ottenendo la base per proseguire nella creazione delle sezioni delle
penne.
Nell'esempio troviamo il procedimento per la creazione del menù della penna nera, che inizia con
l'istanziazione di un oggetto JMenuTool, il quale è un'estensione della classe JMenu di Java, con in
aggiunta i metodi per impostare e conoscere il tool attualmente selezionato per quella penna
(getTool e setTool) ed il metodo per avere il codice colore della penna associata a quel menù.
In seguito viene creato un oggetto PenToolsInfo (verrà analizzato meglio in seguito) che
rappresenta la classe incaricata di preservare i dati impostati dall'utente per quel che riguarda le
caratteristiche fisiche di ciò che si vuole disegnare.
Per rendere esteticamente semplice la barra abbiamo deciso di adottare per ogni penna il colore che
la caratterizza come sfondo del menù. Questo lo possiamo vedere dal codice, dove troviamo i
metodi setOpaque, setBackground e setForeground, dove nell'esempio vediamo che il colore di
sfondo impostato è il nero, e quello della descrizione del menù bianco. E' stato inoltre adottato un
tasto apposito per richiamare il menù tramite tastiera, sfruttando il metodo di JMenu setMnemonic.
Altra funzione adottata molto importante per dare al software che fa uso del menù di penna, un
riferimento facile da trovare e verificare e per ricevere le informazioni sui tool selezionati, è data da
getAccessibleContext().setAccessibleDescription, che imposta per quel menù una descrizione
accessibile al momento dell'azione eseguita su quel menù. Come vedremo in seguito infatti, al
momento della selezione di una qualsiasi azione di un qualsiasi menù, tramite la suddetta funzione è
possibile ricavare in maniera veloce di quale penna stiamo cambiando strumento.
Arrivati a questo punto, ci si trova alla chiamata della funzione che crea i sottomenù delle penne.
Tramite il metodo createMenu(JMenu menu,int actionevent, String Pencolor) si possono creare i
40
sottomenù personalizzati per le penne. Nel nostro esempio la funzione viene richiamata con i
parametri dati dal JMenuTool della penna nera, dall'action event dato dalla pressione del tasto ALT,
e dalla stringa “Black” che caratterizza il colore della penna per la quale si vogliono creare le
possibili azioni. Dopo aver quindi creato menù e sottomenù non rimane altro che aggiungere il tutto
alla toolbar, inserendo subito dopo la parte della penna uno spazio vuoto, al fine di avere ogni menu
di penna staccato dagli altri, tramite la funzione Box.createHorizontalGlue.
Questo procedimento viene applicato in maniera identica per tutte le penne, fatta eccezione per il
colore e le stringhe impostate, a parte per il cancellino. In questo caso, vi sono due variazioni: la
prima è verificata al momento della creazione dell'oggetto PenToolsInfo, dove invece che
specificare solamente il colore (per il cancellino è il bianco) definiamo anche il tool da assegnare al
cancellino stesso (abbiamo deciso che, vista la scarsa precisione di questo strumento, l'unica azione
che potrebbe eseguire correttamente è l'eliminazione degli oggetti). L'altra variazione è data dalla
mancanza della chiamata al metodo createMenu poiché, per la motivazione appena descritta,
abbiamo deciso di assegnare al cancellino una sola possibile azione.
Infine, dopo aver istanziato tutti i menù e le loro relative azioni, impostiamo la barra dei menù
appena creata come JMenuBar della finestra principale.
Con i passi eseguiti fino ad ora, ci troviamo ad avere una finestra senza decorazioni, che presenta 5
menù, ognuno di un determinato colore. La funzione createMenu non verrà descritta in questo
paragrafo, poiché va scritta in base alle proprie esigenze di software, e non è legata al
funzionamento base della toolbar, ma a quello specifico del programma interfacciato alla barra
stessa.
Facendo un passo indietro troviamo un oggetto particolare, creato ad inizio funzione. Si tratta di
ToolBarListener che definisce un action listener per la toolbar appena descritta.
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
JMenuItem menuitem = (JMenuItem) event.getSource();
AccessibleContext ac = menuitem.getAccessibleContext();
AccessibleContext penac = ac.getAccessibleParent().getAccessibleContext();
String penname = penac.getAccessibleDescription();
int menunumb = -1;
if (penname.equals("Black Pen")) menunumb=0;
else if (penname.equals("Red Pen")) menunumb=2;
else if (penname.equals("Eraser")) menunumb=4;
else if (penname.equals("Green Pen")) menunumb=6;
else if (penname.equals("Blue Pen")) menunumb=8;
41
if (!command.equals("Setup")){
barFrame.setToolByNumber(menunumb,command);
barFrame.resetValues(menunumb,command);
AccessibleContext mac = barFrame.getMenubar().getAccessibleContext();
JMenu selectedmenu = (JMenu) mac.getAccessibleChild(menunumb);
selectedmenu.setName(command);
selectedmenu.setText(command);
}
if (command.equals("Setup")){
String tool = barFrame.getToolByMenuNumber(menunumb);
if (tool.equals("Move")){
JOptionPane.showMessageDialog(null,"ATTENZIONE:\n Lo
strumento di movimento non\n necessita di
opzioni","Warning", JOptionPane.WARNING_MESSAGE);
}
else if (tool.equals("Eraser")){
JOptionPane.showMessageDialog(null,"ATTENZIONE:\n Lo
strumento per la cancellazione\n non necessita di
opzioni","Warning", JOptionPane.WARNING_MESSAGE);
}
else { new SetupFrame(tool,menunumb,barFrame); }
}
}
Codice 4: Codice relativo alla funzione di gestione delle azioni eseguite sulla toolbar.
Nell'esempio vediamo cosa la nostra classe esegue in base all'azione ricevuta. In
particolare segnaliamo la modifica del testo all'interno dei menù e la gestione del frame
di setup delle proprietà degli oggetti.
Di questa classe poniamo particolare attenzione al metodo richiamato in caso di selezione di un
elemento di uno dei menù (actionPerformed). Nel momento in cui viene scelto un elemento del
menù per una qualsiasi penna, il codice nel riquadro sopra (Codice 4) viene automaticamente
eseguito. All'interno di questa funzione possiamo vedere che, per prima cosa vengono letti il
comando e l'oggetto che hanno causato la chiamata del metodo. Tramite questi due elementi
ricaviamo, attraverso la struttura dei contenuti accessibili implementati all'interno dei menù Java, la
stringa che descrive la penna utilizzata (nel nostro caso otteniamo una stringa rappresentante il
colore della penna).
Dopo aver ottenuto il nome della penna, verifichiamo quale sia quella in uso impostando un numero
42
che identifica univocamente il menù. Questo valore (menunumb) è ottenuto a seguito della
numerazione automatica dei menù all'interno di una JMenuBar poiché ad ognuno è assegnato un
numero intero, come se la barra fosse un array.
Va detto che come si vede nel codice, la numerazione manca dei valori dispari, ma questo non è un
errore o un difetto ma è semplicemente dato dal fatto che oltre ai menù anche gli “spazi” inseriti tra
un menù e l'altro appartengono agli oggetti numerati.
Passando invece all'istruzione condizionale successiva, troviamo un gruppo di codice racchiuso
dalla condizione sul comando che ha scaturito la chiamata al listener. Se tale comando non è infatti
il comando di setup (nel nostro caso è l'elemento che ci permette di cambiare i valori fisici
caratteristici degli oggetti), viene impostato come strumento per tale penna quello scelto dal menù,
quindi vengono reimpostati i valori per quel tipo di oggetto che si vuole utilizzare (in seguito
vedremo meglio il perché).
Come ultima cosa viene cambiata la label grafica del menù, che cambia rappresentando il nome
della funzione scelta. Questo fatto merita di una menzione particolare, perché in fase di utilizzo del
programma se consideriamo la disponibilità di quattro penne e che in mancanza di questa
caratteristica l'utente debba ricordarsi per ogni penna quale strumento sia stato scelto, capiamo
immediatamente la difficoltà della persona che utilizza il programma nel memorizzare tutte le
combinazioni. Con questo piccolo accorgimento invece, non c'è bisogno di ricordare nulla, è
sufficiente invece guardare sullo schermo il nome rappresentato nel menù (il colore della penna è lo
sfondo della scritta) per sapere quale penna prendere in mano per utilizzare un determinato
strumento.
In caso invece di scelta del sottomenù di setup si effettua il controllo del tool attualmente in uso per
quella penna, il quale se è Move o Eraser non presenta possibili modifiche alle caratteristiche (non
ci sono proprietà per questi due strumenti) e compare quindi un pop up che avverte l'utente della
scelta errata. Per tutti gli altri casi invece viene istanziato un nuovo frame di setup.
Questa finestra di setup è estensibile in base all'ambiente software in cui si inserisce la toolbar, con
il vincolo di richiamarne il costruttore con questa firma:
SetupFrame(String tool,int menunumb,ToolbarFrame barFrame)
Seguendo questa direttiva, ed implementando una funzione per il salvataggio dei dati (nel nostro
caso la funzione saveValues modifica i valori all'interno della classe PenToolsInfo) è possibile
sfruttare la chiamata alla finestra di setup come visto sopra. Nel nostro caso specifico abbiamo
implementato la finestra in modo che al momento della sua apertura, i valori precedentemente scelti
(o quelli di default) vengano automaticamente visualizzati in un'area di testo apposita, e che tali
valori vengano utilizzati come dati iniziali all'interno dei campi di selezione (come si vede in Figura
5.1 i campi sono rappresentati tramite degli spinner, poiché una classica riga di testo obbligherebbe
l'utente a fare uso della tastiera, azione che come detto fin dall'inizio vogliamo evitare).
43
Figura 5.1: Selezione della finestra di setup.
Come mostra la figura l'azione per la penna nera è impostata sullo strumento cerchio. Al
momento della selezione dell'opzione di setup (parte sinistra), viene visualizzata la finestra di
modifica delle proprietà (destra) che permette di cambiare le caratteristiche fisiche
dell'oggetto, nello specifico del cerchio.
Vediamo ora invece quello che rappresenta il cuore della dinamicità della barra, cioè la classe che si
incarica di memorizzare e preservare i dati riguardanti azioni e proprietà di ogni penna. Stiamo
parlando di PenToolsInfo. All'interno di questa classe troviamo alcuni importanti campi privati, che
serviranno appunto alla gestione del flusso di informazioni con ToolBarListener. I due più
importanti sono senz'altro LastTool ( tipo String, rappresenta il nome del tool attualmente in uso per
ogni penna) e PenColor ( tipo di classe Color, necessario per differenziare ogni oggetto
PenToolsInfo dagli altri). Per poter adattare l'interfaccia utente ad un qualsiasi programma esterno
bisognerà quindi estendere questa classe, personalizzando i metodi per il “get” e per il “set” dei
valori. Nel nostro esempio abbiamo creato i metodi di get e di set per ogni proprietà degli oggetti (
density, friction, restitution, squareside, linewidth, arrowdistance e circleradius) ed abbiamo
aggiunto delle funzioni per il reset dei dati. Come abbiamo visto infatti nella funzione
actionPerformed (Codice 4) ogni volta che si seleziona uno strumento diverso da “Setup” viene
chiamato il metodo resetValues(menunumb, command) il quale dato un ID del menù (per esempio 0
per la penna nera) ed un comando (nel nostro esempio può essere il comando cerchio) richiama a
sua volta il corrispondente metodo di reset dei valori ( per noi setupCircle ) che reimposterà i
parametri a quelli di default scelti in fase di programmazione.
I dati più volte menzionati fino ad ora, vengono tutti immagazzinati all'interno della classe PTI
(PenToolsInfo) che include i campi privati appositi per contenere tali valori (nel caso della fisica
2D, abbiamo la classe PenToolsInfo che racchiude i campi per densità, attrito, raggio del cerchio e
tutti gli altri più volte menzionati).
44
5.2 Cattura degli eventi generati dalla LIM
Una volta sviluppata la toolbar che gestisce e comanda le azioni associate alle penne ci troviamo
davanti al problema della gestione degli input sulla lavagna. In linea teorica l'ascolto degli eventi
non dovrebbe essere problematico poiché, come visto nel Capitolo 3.1 (Descrizione API Java), la
libreria JAR messa a disposizione da SmartBoard ci permette di effettuare in maniera automatizzata
tale gestione. A conti fatti però il listener fornitoci dalle API non è sufficiente ad eseguire la nostra
cattura degli eventi. Il problema infatti nasce dal metodo in cui il motore fisico viene mostrato
graficamente, cioè tramite le vecchie classi AWT e non tramite quelle più recenti appartenenti al
package SWING. A causa di questa scelta implementativa attuata dagli ideatori di JBox2D, i nostri
oggetti appartenenti alla libreria SBORDA non riescono a catturare correttamente gli eventi. Dopo
svariati tentativi e dopo aver provato qualsiasi tipo di raggiro al problema, siamo giunti ad una
conclusione indolore e con le stesse funzionalità rispetto all'idea iniziale.
Dopo essere riusciti a fare in modo che SBSDKListener riconosca gli eventi sulla pentray della
lavagna e che arrivati a questo punto, ogni pressione delle penne sulla lavagna viene riconosciuta
come un click del mouse, abbiamo implementato un apposito “mouseListener”, collegato all'action
listener BoardListener, che cattura gli eventi sulla pentray. La tecnica adottata per far si che le
azioni compiute con la penna siano differenziate da quelle del mouse si basa su alcuni flag
incrociati tra le due classi listener (BoardListener e Man, che sta per Mouse Action Notify), i quali
fanno in modo che, una volta presa in mano una penna, la classe Man riconosca questa situazione
ed in caso di evento di pressione, click o drag si comporti di conseguenza, simulando di fatto le
chiamate apposite integrate in BoardListener. All'interno di quest'ultima classe, troviamo le classi
viste nel Capitolo 3.1, con alcune di esse implementate.
public void onEraser(int iPointerID) { mouse.setPenMethod(true); }
public void onNoTool(int iPointerID) { mouse.setPenMethod(false); }
public void onPen(int iPointerID) { mouse.setPenMethod(true); }
Codice 5: Nel riquadro le funzioni implementate in BoardListener.
In caso di evento da parte della lavagna del tipo onPen o onEraser (nel caso in cui si
tolga uno dei suddetti strumenti dalla pentray) la funzione setPenMethod della classe
Man verrà richiamata con parametro true, in caso di posa di qualsiasi strumento, si
avrà la stessa chiamata,ma con parametro false.
Come possiamo vedere nel riquadro, in base all'evento occorso, il metodo della classe Man viene
eseguito con parametro true o false. Abbiamo true se uno strumento viene preso in mano dall'utente,
rimuovendolo dalla pentray, mentre il parametro sarà false in caso di posa di un qualsiasi strumento
(sia esso il cancellino o una penna). Tutte le altre funzioni di BoardListener non sono state
implementate per più motivi, alcune per inutilizzo (onCircle, onLine ed onPrint per esempio non
vengono mai eseguite) altre per scelta, come nel caso dei metodi riguardanti la modalità senza
proiezione che abbiamo scelto di non implementare perché il nostro proposito di interfaccia si basa
45
proprio sull'idea che l'utente faccia uso dell'immagine proiettata sulla lavagna.
Seguendo quindi la gerarchia dei metodi arriviamo alla classe che sostituisce di fatto BoardListener
nell'esecuzione del codice in caso di eventi. Di questa classe vedremo in dettaglio per prime le
funzioni automaticamente richiamate al momento dell'azione corrispondente, in seguito
analizzeremo nel dettaglio i metodi adottati per l'attivazione dell'azione scelta.
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
if (pen){
if (sd.parent.shiftKey) {
return;
}
OnPen(e);
}
}
}
public void mouseReleased(MouseEvent e) {
shapedrawing.mouse();
if (e.getButton() == MouseEvent.BUTTON1){
if (pen){
if (sd.parent.shiftKey) {
return;
}
OnPenEnd(e);
}
}
}
Codice 6: Metodi implementati per la gestione dei click del mouse.
La gestione della pressione sulla lavagna viene verificata e controllata principalmente
tramite due funzioni, OnPen per l'azione di pressione, e OnPenEnd per l'azione di
rilascio.
46
Vediamo in qui questo caso le funzioni attive in fase di pressione e rilascio del mouse. Al momento
della pressione con il mouse (o grazie alla nostra implementazione, con la lavagna) viene eseguito il
controllo sul pulsante del mouse utilizzato. Tutte le routine necessarie al disegno degli oggetti,
vengono infatti eseguite solo se si preme il tasto sinistro del mouse (MouseEvent.BUTTON1)
oppure se si preme con un pennarello. Questo va fatto perché il tasto destro e la rotella vengono
utilizzati per lo zoom e lo spostamento della visuale. Una volta eseguito questo controllo quindi si
passerà alla verifica del flag di penna che è indicato da un valore booleano (pen) il quale viene
appunto modificato all'interno di BoardListener (come visto nelle funzioni del Codice 5). Tale flag
ci indica se stiamo utilizzando una penna (valore a true) oppure se tutti gli strumenti della lavagna
sono nella loro sede della pentray (valore a false). In caso di esito positivo troviamo un altro
controllo riguardo alla pressione del tasto Shift sulla tastiera ( in tal caso non viene disegnato
niente ) e quindi si può procedere alla funzione OnPen, che analizza ed esegue le azioni corrette in
base alla situazione. Analogamente al momento del rilascio del tasto del mouse ( o la fine della
pressione con la penna ) viene eseguito del codice che termina con la chiamata ad OnPenEnd, che
di fatto richiamerà il corretto metodo di disegno. Ad inizio metodo invece troviamo la chiamata alla
funzione appartenente a ShapeDrawing, che serve nello specifico al motore fisico e quindi la
vedremo in seguito.
public void OnPen(MouseEvent e){
Color pencolor = tbm.getSDK().getToolColor(iPointerID);
int tooltype = tbm.getSDK().getToolType(iPointerID);
if (tooltype == 2) {}
else {
int menunumber = this.getNumberByPencolor(pencolor);
mousecheck = true;
String tool = barFrame.getToolByMenuNumber(menunumber);
if (tool.equals("Circle")){
int x = e.getX();
int y = e.getY();
startpos.setX(x);
startpos.setY(y);
shapedrawing.mouse(new Vec2(x,y), Man.PRESSED);
}
...
}
47
public void OnPenEnd(MouseEvent e){
Color pencolor = tbm.getSDK().getToolColor(iPointerID);
int ttype = tbm.getSDK().getToolType(iPointerID);
if (ttype == 2) {
String tool = barFrame.getToolByMenuNumber(4);
if (tool.equals("Eraser")){ shapedrawing.destroy(startpos); }
} else {
int menunumber = this.getNumberByPencolor(pencolor);
pti = barFrame.getPTIbyMenuNumber(menunumber);
String tool = barFrame.getToolByMenuNumber(menunumber);
if (tool.equals("Circle")){
int x = e.getX();
int y = e.getY();
endpos.setX(x);
endpos.setY(y);
shapedrawing.createCircle(startpos, endpos, pti);
mousecheck=false;
}
}
Codice 7: OnPen e OnPenEnd.
I due metodi rappresentano le funzioni in fase di pressione e rilascio del mouse che si
incaricano di gestire ed analizzare la situazione in corso.
Al momento della pressione sulla lavagna, come visto in precedenza, viene chiamato il metodo
OnPen, il quale da come si vede nel riquadro acquisisce innanzitutto le proprietà dello strumento
con cui il tocco è stato effettuato, leggendo colore e tipo dello strumento ( le penne appartengono al
tipo 1, il cancellino al tipo 2) tramite iPointerID ( definito nel Capitolo 3.1). In base al tipo di
strumento utilizzato, ci troviamo in due possibili situazioni: se abbiamo utilizzato il cancellino non
viene eseguita nessuna azione, poiché come detto in precedenza questo elemento ha la sola utilità di
cancellare un oggetto, e quindi gli unici dati che ci servono alla cancellazione li possiamo ricavare
al momento del rilascio della pressione. Se invece stiamo utilizzando una penna dobbiamo acquisire
i dati dello strumento (colore della penna e tool attualmente attivo per essa), attivare il flag per
l'inizio disegno (questo flag viene utilizzato dalla classe grafica del motore fisico, e quindi lo
vedremo in seguito) ed infine selezionare la routine relativa al tool attivo. Nell'esempio mostriamo
il codice nel caso dello strumento Cerchio (il codice è molto simile per le altre azioni) che salva in
un array interno alla classe i parametri relativi alle coordinate dell'evento, inviandoli anche alla
classe ShapeDrawing tramite il metodo mouse, al fine di poter rendere graficamente un'anteprima
48
delle posizioni percorse con il cursore.
Dopo aver terminato la pressione sulla lavagna invece ci troviamo all'interno del codice di
OnPenEnd che come ad inizio evento acquisisce le informazioni sullo strumento (questo per una
questione di sicurezza) ed anche in questo caso differenzia l'esecuzione in base al tipo di strumento
utilizzato: utilizzando il cancellino effettuiamo un controllo di sicurezza sul comando selezionato
per il menù di questo strumento, ed in caso di esito positivo eseguiamo la funzione di eliminazione
dell'oggetto cliccato, appartenente alla classe ShapeDrawing. Utilizzando invece una penna,
seguendo l'esempio del comando Cerchio vediamo come vengano salvate anche questa volta le
coordinate dell'evento per essere utilizzate, assieme a quelle salvate all'interno di OnPen e
all'oggetto PenToolsInfo relativo alla penna utilizzata, come parametri del metodo di disegno di
ShapeDrawing apposito per quel comando ( in questo caso createCircle ). Effettuata la chiamata a
questo metodo si reimposta il flag mousecheck a false per indicare la fine del disegno.
5.3 Interfacciamento a JBox2D
Il menù di penne creato deve quindi essere interfacciato al software che ne fa uso, nel nostro caso il
motore di JBox2D.
La parte più importante del collegamento tra toolbar e simulatore di fisica, è rappresentata dalla
gestione dei dati e da come vengono utilizzate le informazioni derivate dai listener già descritti.
Per quanto riguarda il primo punto come detto in precedenza sfruttiamo una classe apposita che
preserva i dati degli oggetti da creare e fornisce metodi per la lettura e la scrittura di tali valori. La
classe in questione è PenToolsInfo, che contiene dei campi privati per il mantenimento delle
proprietà fisiche degli oggetti da disegnare.
public class PenToolsInfo {
private String LastTool;
private Color PenColor;
private float radius = 0.6f;
private float side = 1.0f;
private float distance = 1.0f;
private float width = 1.0f;
private float density = 2f , restitution = 0.2f , friction = 0.3f;
public PenToolsInfo(Color penna){
this.PenColor = penna;
this.LastTool = "Move";
}
49
public void resetValues(String command){
if (command.equals("Circle")) setupCircle();
if (command.equals("Rectangle")) setupSquare();
if (command.equals("Arrow")) setupArrow();
if (command.equals("Line")) setupLine();
Color temp = PenColor;
PenColor = temp;
}
public void setupCircle(){
radius
= 0.6f;
density
= 5.0f;
restitution
= 0.3f;
friction
= 0.2f;
Codice 8: Campi e alcuni metodi della classe PenToolsInfo.
Nel riquadro vediamo i campi privati della classe, ed alcuni metodi utili alla gestione dei
valori.
Come si può vedere nel riquadro la classe possiede tutti i parametri necessari alla gestione dei dati e
delle azioni per le penne. Creando infatti un oggetto di questa classe per ogni penna diversa (anche
per il cancellino), possiamo differenziare il comportamento per ognuna di esse. Se viene richiamato
il costruttore della classe senza specificare lo strumento da associare ad una determinata penna
( PenColor è il colore della penna), a quell'oggetto verrà automaticamente assegnato il comando di
“Move” (spostamento) degli oggetti simulati. Subito dopo invece possiamo notare i campi che
contengono i parametri delle forme che verranno create in JBox2D. Ogni volta che viene
selezionato un determinato tool all'interno del menù di penne viene richiamato (come visto in
precedenza) il metodo resetValues di questa classe. In base al tool specificato nella firma di questa
funzione verrà eseguita l'azione corrispondente. Per farne un esempio, vediamo quella del cerchio;
ogni parametro relativo a tale oggetto viene ripristinato al valore di default specificato da parte del
programmatore. Così facendo otteniamo il classico effetto di ritorno alle impostazioni iniziali.
Per quanto riguarda il collegamento tra toolbar va detto il metodo con cui JBox2D utilizza i dati
ricevuti al momento della cattura degli eventi della lavagna.
Come abbiamo visto nella sezione precedente ogniqualvolta si rilascia la penna dalla superficie il
listener esegue il metodo relativo all'oggetto specificato, utilizzando tre parametri specifici
(abbiamo visto l'esempio del cerchio shapedrawing.createCircle(startpos, endpos, pti) ). Questi tre
parametri rappresentano il punto di inizio dell'evento dato dalla penna, il punto di fine, e l'oggetto
PenToolsInfo come appena visto. Per ora ci limiteremo ad analizzare i primi due (analizzeremo
l'utilità del terzo nel prossimo capitolo), per spiegare come disegnare correttamente gli oggetti.
Abbiamo dovuto scartare l'idea di un riconoscimento delle forme poiché non abbiamo trovato
50
pattern già pronti, e come per la scrittura a mano ci saremmo trovati di fronte ad un problema
difficilmente risolvibile. Abbiamo quindi optato per una soluzione comunque semplice per l'utente,
che ci permetta di disegnare rapidamente l'oggetto. La scelta si basa quindi sulla distanza percorsa
dal cursore come parametro principale per il disegno. I due vettori startpos ed endpos infatti
appartengono ad una classe scritta appositamente per questa situazione.
public class VecPos2 {
private float xpos;
private float ypos;
public float getDist(VecPos2 vp) {
float x2 = vp.getX();
float y2 = vp.getY();
return getDist(x2,y2);
}
public float getDist(float x2,float y2) {
float x1 = xpos;
float y1 = ypos;
float radice = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
float distanza = (float) Math.sqrt(radice);
return distanza;
}
public Vec2 toVec2(){
Vec2 vet = new Vec2(xpos,ypos);
return vet;
}
public void vecToPos(Vec2 vet){
this.xpos = vet.x;
this.ypos = vet.y;
}
}
Codice 9: Classe VecPos2 utilizzata per ottenere le dimensioni dell'oggetto da disegnare.
Nel riquadro possiamo vedere come la classe si riduca a due campi privati ed alcune semplici
funzioni. I campi rappresentano coordinate orizzontali e verticali del punto in cui è avvenuto
l'evento, per i metodi invece li vediamo singolarmente.
51
Innanzitutto vediamo come ci sia due volte il metodo getDist con due diverse firme, questo è stato
fatto per permettere la chiamata dall'esterno in due diversi modi, infatti il risultato è lo stesso.
Specificando un oggetto dello stesso tipo infatti, viene eseguito il metodo con le due coordinate
prese singolarmente. Ottenuti questi due valori, tramite una semplicissima formula matematica
basata sul teorema di Pitagora, viene restituita la distanza tra i due punti (quello dell'oggetto tramite
cui è stata chiamata la funzione e quello specificato nella firma della funzione). Gli altri due metodi
invece servono per il casting dell'oggetto restituendo un vettore Vec2 utile per le classi di JBox2D
(toVec2 ), oppure per modificare l'oggetto attuale, impostando le sue coordinate come quelle del
vettore dato in input (vecToPos).
Al momento della creazione di un cerchio o altra figura in JBox2D i due oggetti VecPos2 verranno
utilizzati per avere una dimensione esatta di quello che si andrà a disegnare. Per fare un esempio,
nel caso del cerchio viene calcolata la distanza tra inizio e fine pressione sulla lavagna, si calcola la
distanza tra i due punti che sarà utilizzata come diametro del cerchio disegnato. Così facendo si ha
una corrispondenza esatta tra quello che si fa fisicamente e la rappresentazione grafica risultante.
52
Capitolo 6: Caso d'uso: Smart Box 2D
Come anticipato in precedenza il software sviluppato rappresenta una simulazione di fisica
bidimensionale, sfruttando il menù di penna visto nei capitoli precedenti.
Abbiamo visto che le funzioni di disegno degli oggetti vengono richiamate attraverso un mouse
listener che fa da filtro tra gli eventi generati dalla lavagna ed il motore fisico. Grazie a questo
“filtro” abbiamo la possibilità di personalizzare il comportamento della nostra toolbar,
semplicemente facendo l'operazione di overriding dei metodi di creazione dei sotto menù (
createMenù ) e quelli di chiamata delle azioni specifiche (nel nostro caso i metodi di disegno degli
oggetti) richiamate tramite la classe Man, in particolare da OnPen e OnPenEnd.
E' stato inoltre brevemente descritto il metodo utilizzato per permettere all'utente di scegliere le
dimensioni degli oggetti da creare. La tecnica scelta per il disegno infatti, si basa sull'input
continuato dell'utente. In fase di dragging del cursore all'interno del sistema fisico simulato l'utente
potrà infatti vedere il percorso tracciato tramite una sottile linea bianca che verrà poi eliminata nel
momento in cui si rilascerà il cursore (smettendo la pressione sulla lavagna). Questo metodo è stato
adottato per ovviare ad un approccio meno multimediale come quello di imporre all'utente una
dimensione prefissata per l'oggetto da disegnare, eseguendo la creazione dopo un click.
Tramite la soluzione proposta invece qualsiasi elemento si voglia creare avrà una dimensione pari
alla distanza minima percorsa tra il punto di inizio ed il punto di fine dell'evento generato dalle
penne. Abbiamo specificato la distanza minima, proprio perché è stato deciso di non misurare
l'intero percorso effettuato dal cursore poiché se, ad esempio, si vuole disegnare un quadrato e si
“disegna” il lato voluto, difficilmente si eseguirà una linea retta, ma più facilmente si traccerà un
percorso simile ad una retta, ma leggermente curvato, con il risultato di aver percorso una distanza
maggiore di quella desiderata.
Espandendo il caso ad un esempio limite possiamo pensare ad un tracciato fatto da una mano poco
ferma che, invece che effettuare una linea leggermente ricurva, ne disegna una molto altalenante,
ottenendo cosi una distanza percorsa di molto maggiore rispetto a quella voluta.
53
Figura 6.1: Disegno degli oggetti. Nella figura vediamo due differenti tracciati. A sinistra un
tracciato abbastanza fermo, l'oggetto disegnato (ad esempio il cerchio) avrà come dimensione
quella del tracciato effettuato. A destra vediamo un tracciato poco fermo. La dimensione
utilizzata è rappresentata dalla distanza tra il primo e l'ultimo punto,e non dal percorso
completo del cursore, che è di molto maggiore rispetto alla distanza effettiva.
Dopo aver analizzato il metodo per la scelta della dimensione degli oggetti, vediamo come tali
oggetti possono essere ricoperti da una texture grafica. All'interno di JBox2D vi è già un metodo per
applicare tale immagine agli elementi ma, tale funzione, non è stata implementata del tutto.
Utilizzandola così come la si trova infatti riusciamo si ad applicare le texture, ma se creiamo più
oggetti velocemente viene generata un'eccezione in runtime che manda in stallo il software.
Applicando correttamente la cattura di tale eccezione abbiamo evitato il crash del programma,
negando il permesso per il disegno di quell'oggetto.
Per cancellare gli oggetti invece ci siamo basati sulla funzione apposita già presente all'interno della
libreria fisica utilizzata. Tale metodo permette di cancellare l'elemento indicato (Body) eliminandolo
sia graficamente che dalla lista degli oggetti dell'ambiente simulato. Per questo motivo nel nostro
programma è permessa la cancellazione degli oggetti dinamici, ma non di quelli statici ( Linee ) che
vengono ancorati all'ambiente e perdono il loro indicatore di massa ( Body ).
Il problema riscontrato in fase di cancellazione è apparso nel momento in cui si cancellava un
elemento che aveva una texture. In quel caso l'oggetto veniva correttamente eliminato, mentre la
texture rimaneva all'interno della rappresentazione grafica, ma non avendo più nessun corpo a cui
rimanere ancorata scivolava verticalmente nel basso dello schermo. Per poter quindi ovviare a
questo problema abbiamo implementato un sistema di mantenimento della corrispondenza tra
immagine ed oggetto tramite una classe apposita, ImageInfo.
54
public class ImageInfo {
private BoundImage immagine;
private ShapeDrawing shaped;
public Hashtable<Body, BoundImage> tableimages;
public ImageInfo(ShapeDrawing sdraw){
this.shaped=sdraw;
tableimages = new Hashtable<Body, BoundImage>();
tableimages.clear();
}
public void add(BoundImage bi){
Body bd = bi.getBody();
tableimages.put(bd,bi);
}
public void remove(Body body){
if (tableimages.containsKey(body)){
immagine = (BoundImage) tableimages.get(body);
shaped.removeImage(immagine);
}
}
}
Codice 10: Classe ImageInfo.
La classe nel riquadro mostra i metodi ed i campi utilizzati per verificare e gestire la
creazione e la cancellazione delle texture applicate agli oggetti. Da come si può vedere,
le informazioni sono gestite tramite un Hash Table.
La classe inserita nel riquadro contiene alcuni campi tra cui un oggetto BoundImage che rappresenta
per JBox2D l'immagine da applicare a ciò che si disegna, un puntatore a ShapeDrawing, cioè la
classe che rappresenta il sistema in cui ci muoviamo, ed un HashTable caratterizzata da una chiave
(Body) ed un oggetto (BoundImage). Tramite questa hashtable possiamo per ogni oggetto Body,
differente per ogni elemento del sistema, ottenere la corrispettiva texture. Possiamo vedere questo
fatto attraverso le funzioni add e remove, nella prima troviamo un solo parametro composto da
BoundImage che di fatto preserva un collegamento al corpo associato. Tramite questo collegamento
otteniamo il Body corrispondente ad aggiungiamo la coppia ad hashtable. In fase di rimozione
55
dell'oggetto invece viene passato il Body, tramite il quale si verifica la sua presenza tra le chiavi di
hashtable, ed in caso positivo si rimuove l'immagine tramite la funzione inserita all'interno della
classe ShapeDrawing, che si incaricherà di eliminare ogni occorrenza della texture in questione.
public void removeImage(BoundImage immagine){
if (boundImages.contains(immagine))
boundImages.remove(immagine);
}
Come possiamo vedere nel riquadro, la funzione verifica l'esistenza della texture tra quelle
attualmente inserite nel sistema, ed in caso affermativo la rimuove dalla lista, evitando cosi che
venga ridisegnata anche in caso di mancanza del corpo ad essa associato.
public void destroy(VecPos2 pos){
Vec2 pos2 = m_debugDraw.screenToWorld(pos.toVec2());
assert m_mouseJoint == null;
Vec2 d = new Vec2(0.001f, 0.001f);
AABB aabb = new AABB(pos2.sub(d), pos2.add(d));
int k_maxCount = 10;
Shape shapes[] = m_world.query(aabb, k_maxCount);
Body body = null;
for (int j = 0; j < shapes.length; j++) {
Body shapeBody = shapes[j].getBody();
if (shapeBody.isStatic() == false) {
boolean inside = shapes[j].testPoint(shapeBody.getXForm(),pos2);
if (inside) {
body = shapes[j].m_body;
break;
}
}
}
if (body != null) {
iinfo.remove(body);
MouseJointDef md = new MouseJointDef();
md.body1 = m_world.getGroundBody();
md.body2 = body;
md.target.set(pos2);
md.maxForce = 1000.0f * body.m_mass;
m_mouseJoint = (MouseJoint) m_world.createJoint(md);
56
}
Shape s = body.getShapeList();
while (s != null){
body.destroyShape(s);
Shape.destroy(s);
s = body.getShapeList();
}
}
Codice 11: Metodo per l'eliminazione degli oggetti.
La funzione destroy si incarica dell'eliminazione dei corpi dal sistema simulato. In
grassetto possiamo vedere la riga di codice aggiunta a quello già presente in JBox2D
per rimuovere correttamente le textures.
Per quanto riguarda il metodo che effettua l'eliminazione degli oggetti dalla simulazione e
dall'interfaccia grafica è stato sfruttato quello già presente in JBox2D, aggiungendoci però una riga
di codice per rimuovere la texture corrispondente al corpo da eliminare. Inizialmente troviamo una
routine che, date delle coordinate in input, verifica se in quell'istante ed a quelle coordinate vi è
presente un elemento di tipo Body. In grassetto nel riquadro sopra troviamo iinfo.remove(body) che,
dato un oggetto iinfo (ImageInfo) come descritto qualche pagina addietro, richiama la sua funzione
per l'eliminazione dell'immagine da hashtable che preserva le corrispondenze tra corpi e texture. La
rimanente parte di codice serve al motore fisico per rimuovere totalmente il corpo selezionato ed
eventuali parti unite ad esso tramite una JointUnion.
Arrivati a questo punto possiamo vedere come gli oggetti vengono creati. Per farlo però, è
necessario ricordare dove le varie proprietà degli oggetti sono state salvate. Vi sono infatti quattro
oggetti PenToolsInfo, uno per ogni penna della lavagna. Ogni oggetto preserva per la penna
corrispondente le informazioni utili a disegnare il tool visualizzato nel menù. Per fare un esempio se
abbiamo scelto per la penna nera l'azione corrispondente al cerchio, vi sarà un oggetto PenToolsInfo
apposito per il pennarello nero che conterrà i dati per il disegno del cerchio. Questi dati come già
visto sono personalizzabili attraverso la selezione del menù setup.
public void createCircle(VecPos2 startpos, VecPos2 endpos,PenToolsInfo pti) {
try {
Vec2 wstart = m_debugDraw.screenToWorld(startpos.toVec2());
Vec2 wend = m_debugDraw.screenToWorld(endpos.toVec2());
VecPos2 pwstart = new VecPos2();
VecPos2 pwend = new VecPos2();
pwstart.vecToPos(wstart);
pwend.vecToPos(wend);
57
float distance = pwstart.getDist(pwend);
CircleDef shapedef = new CircleDef();
if (distance > 0) shapedef.radius = distance;
else {
shapedef.radius = pti.getRadius();
distance = pti.getRadius();
}
shapedef.density
= pti.getDensity();
shapedef.restitution = pti.getRestitution();
shapedef.friction
= pti.getFriction();
BodyDef bodydef
= new BodyDef();
Vec2 worldvec = wstart;
bodydef.position = new Vec2(worldvec.x, worldvec.y);
Body myBody = m_world.createBody(bodydef);
myBody.createShape(shapedef);
myBody.setMassFromShapes();
PImage myImage = parent.loadImage("circ.png");
Vec2 localOffset = new Vec2(0.0f, 0f);
float scale = distance*2 / myImage.width;
float rot = 0f;
bindImage(myImage, localOffset, rot, scale,myBody);
} catch (NullPointerException npe) {
String error = npe.toString();
System.err.println("[DEBUG]::[ERRORS] --- "+ error );
}
}
Codice 12: Metodo per la creazione dei cerchi.
Il primo passo eseguito nel metodo di createCircle è dato dalla trasformazione delle coordinate deri­
vate dall'evento della penna, in coordinate del mondo simulato. Una volta eseguito tale passo a par­
tire da queste coordinate vengono creati due oggetti VecPos2 che vengono usati subito dopo per cal­
colare la distanza tra inizio e fine dell'evento.
58
Dopo aver creato un nuovo oggetto CircleDef, cioè una definizione di forma di un elemento cer­
chio, verifichiamo la distanza percorsa dal cursore. La verifica viene fatta perché in caso di click
con la penna e non di pressione continuata la distanza risulta nulla e viene creato un cerchio senza
proprietà fisiche (a causa di alcune scelte degli sviluppatori del motore fisico). Per evitare ciò abbia­
mo fatto in modo che se la distanza è maggiore di zero (cioè se c'è stata una pressione continuata) il
raggio utilizzato per il cerchio è la distanza effettiva, altrimenti viene utilizzata la grandezza specifi­
cata nel setup del cerchio (se non specificata viene utilizzata una grandezza di default).
Una volta definito il raggio ( o ad esempio per il quadrato la dimensione del lato), procediamo a de­
finire gli altri parametri caratteristici dell'oggetto. La densità, il coefficiente di rimbalzo e quello di
attrito vengono infatti letti dalla classe PenToolsInfo come visto prima, sfruttando quindi le impo­
stazioni scelte dall'utente. La riga successiva definisce un nuovo oggetto BodyDef che rappresenta
la definizione delle caratteristiche del corpo che si andrà a creare. Si procede quindi con la defini­
zione della posizione del corpo del cerchio che verrà creato sfruttando le coordinate di inizio pres­
sione.
Arrivati a questo punto troviamo due funzioni essenziali per la fisica degli oggetti: createShape
serve per creare fisicamente la forma del cerchio cioè per inserirlo nella simulazione, mentre
setMassFromShape è la funzione che abilita il calcolo delle forze fisiche in gioco per il movimento
simulato dell'oggetto. Senza questa importantissima funzione infatti l'oggetto che andiamo a creare
viene interpretato dal motore fisico come un ostacolo o come un delimitatore (ad esempio il terreno). Abbiamo sfruttato questa caratteristica del motore per poter dare all'utente la possibilità di
creare appunto terreni, percorsi o “scatole” in cui contenere gli oggetti creati. Lo strumento linea
infatti permette il disegno allo stesso modo del cerchio, ma manca dell'opzione setMassFromShape,
risultando appunto inamovibile anche se non poggiata sulla base dell'ambiente.
Le righe di codice che seguono servono per applicare la texture all'immagine. Per prima cosa impo­
stiamo un offset per l'immagine, nel nostro caso ha valore zero perché vogliamo inserire la figura al
centro del cerchio. In seguito calcoliamo il valore tramite il quale l'immagine verrà scalata. Rica­
viamo questo dato grazie al rapporto tra il diametro del cerchio creato e la larghezza della texture
(essendo un cerchio larghezza ed altezza si equivalgono), ottenendo un valore di scala preciso per
ogni oggetto creato. È possibile inoltre impostare un valore di rotazione per la texture nel caso in
cui ci sia bisogno, ma nel nostro caso non ne abbiamo la necessità e quindi gli daremo un valore
pari a zero. Dopo aver valutato tutti i parametri appena descritti possiamo eseguire il metodo di
associazione dell'immagine al cerchio tramite bindImage, la quale avrà tra i suoi parametri oltre a
quelli appena descritti, anche l'oggetto Body rappresentante il cerchio. Attraverso questo metodo
vengono richiamata la funziona di riempimento di hashtable vista nel riquadro Codice 10.
Tutto quanto è stato visto a riguardo di questi passi per la creazione degli oggetti è racchiuso
all'interno di un blocco di cattura delle eccezioni, in particolare l'eccezione catturata è del tipo
NullPointerException e viene generata dal metodo createShape. Il bug è attribuito a JBox2D dai
suoi sviluppatori, ma non ne è nota la sua natura, poiché avviene in diverse circostanze ogni volta
diverse e non dipende in alcun modo dai parametri personalizzati.
In caso di sollevamento di tale eccezione l'oggetto non viene creato per evitare che come da noi
riscontrato, ci si trovi con un cerchio che non ha una sua massa e quindi privo di movimento. Va
comunque specificato che l'eccezione si presenta occasionalmente se la creazione degli oggetti
viene effettuata senza un'eccessiva rapidità. Continuando infatti a generare eventi ed a creare diversi
oggetti il motore fisico tende a sollevare l'eccezione con maggior frequenza.
59
Per quanto riguarda il programma completo possiamo seguire i passi per mostrare come vengono
elaborati i dati ricevuti e come il programma si comporta.
Analizzeremo il processo da eseguire per creare un cerchio utilizzando la penna nera, visualizzando
passo per passo dove è possibile effettuare le azioni e le scelte descritte nei capitoli visti fino ad ora.
Figura 6.2: Uno screenshot del programma appena aperto.
Nell'immagine possiamo vedere l'ampio spazio a disposizione per il disegno e
l'interazione con gli oggetti. Come premesso nei capitoli precedenti, l'interfaccia
sviluppata è semplice ed occupa il minimo spazio se confrontata con la GUI del motore
fisico.
In Figura 6.2 possiamo vedere come appare graficamente il programma una volta aperto. Troviamo
una grande sezione di schermo nera che rappresenta lo spazio aperto, cioè il posto dove gli oggetti
si muoveranno, nella parte bassa in verde possiamo vedere la rappresentazione nel motore fisico del
terreno ed in fronte ad essa troviamo il menù come appare inizialmente. Ogni penna è caratterizzata
dal proprio colore ed il titolo che caratterizza i menù è in questo momento uguale al nome della
penna corrispondente. Per continuare con il nostro intento, dobbiamo quindi selezionare il menù
Black Pen e quindi la voce Circle, ottenendo come risultato all'interno del software l'attivazione del
60
listener per la toolbar ed il conseguente avvio del metodo associato all'azione eseguita.
Figura 6.3: Selezione delle proprietà per l'oggetto cerchio.
Selezionando dal menù della penna interessata la voce Setup compare la finestra per la
personalizzazione dei parametri fisici per l'oggetto da disegnare. In figura vediamo il caso
preso in esame nell'esempio; il setup del cerchio.
Dopo aver selezionato il cerchio per la penna nera modifichiamo le proprietà del cerchio da creare.
Selezionando nuovamente Black Pen apriamo tale menù e clicchiamo sulla voce Setup. Dal punto di
vista dei metodi in questa situazione il listener della toolbar vista l'azione di setup controlla il tool
precedentemente attivo per quella penna e quindi avvia e mostra la sezione di setup per lo strumento
selezionato. Compare quindi la finestra per la modifica dei parametri del cerchio, possiamo variare
a nostra discrezione il valore del raggio di default da utilizzare in caso di click (come visto in
precedenza). Le altre proprietà personalizzabili sono la densità del corpo, il suo coefficiente di
rimbalzo (o elasticità) e quello di attrito. Una volta specificati i valori è sufficiente chiudere la
finestra per far si che questi vengano salvati, tramite la funzione saveValues appartenente alla classe
SetupFrame.
A questo punto ci troviamo ad aver preparato il motore fisico per il disegno del cerchio con le
proprietà specificate e procederemo quindi con il tracciare la dimensione del raggio con la penna
nera. Come già anticipato prima il percorso da effettuare con il pennarello non è la circonferenza
del cerchio da creare, ma il suo raggio.
Nella figura successiva possiamo vedere il tracciato indicante il raggio del cerchio per il nostro
esempio.
61
Figura 6.4: Tracciatura della distanza del cerchio.
Tracciando con la penna un percorso semi lineare come in Figura 6.4 otteniamo la chiamata in
primo luogo della funzione OnPen al momento della pressione con la penna, quindi quando la
penna verrà tolta dalla superficie della lavagna verrà eseguito il metodo OnPenEnd. Come visto in
precedenza questo metodo verifica il tool attivo per il pennarello utilizzato e quindi effettua la
chiamata al metodo createCircle, il quale si incaricherà della creazione di un cerchio che ha come
raggio la distanza percorsa dal cursore, e come parametri fisici quelli indicati nella finestra di setup
(Figura 6.3).
Una volta creato il cerchio lo troveremo all'interno dello spazio come in Figura 6.5.
62
Figura 6.5: L'oggetto cerchio è stato creato e ne viene simulato il comportamento fisico.
Il cerchio è stato creato dalla funzione createCircle ed è stato inserito nel sistema. Ogni suo
movimento risulta ora come una simulazione fisica. Le forze in gioco vengono calcolate, misurate
ed utilizzate per modificare il movimento del cerchio. È possibile inoltre utilizzando il mouse (o il
dito sulla lavagna) spostare l'oggetto e posizionarlo dove si desidera.
63
64
Capitolo 7: Conclusioni
È stata proposta una soluzione al problema posto in fase di introduzione riguardo allo sviluppo di
un'interfaccia sfruttabile nell'ambiente delle lavagne interattive multimediali.
La soluzione proposta rappresenta quindi un valido candidato all'utilizzo con tali strumenti.
L'attenzione è stata particolarmente posta sulla semplicità d'uso e sull'alto tasso di interattività che
l'interfaccia deve permettere. Abbiamo mostrato, oltre alla soluzione sviluppata, altre eventuali
proposte, elencandone i motivi per cui non sono state adottate.
Sono state innanzitutto mostrate le peculiarità delle lavagne interattive multimediali elencandone le
caratteristiche, i punti di forza e le mancanze di questa tecnologia. Dopo aver differenziato le
diverse tecniche adottate per la gestione degli input, abbiamo analizzato le API messe a
disposizione dal costruttore della lavagna utilizzata, che in questa sede è la SmartBoard di SMART
Technologies. Sono stati mostrati i metodi appartenenti alle API, i possibili utilizzi di tali classi ed i
loro limiti. In seguito sono state effettuate delle considerazioni sulle caratteristiche che l'interfaccia
utente oggetto di questa tesi deve avere, descrivendo le motivazioni che inducono a tali scelte.
Una volta stabilite le richieste da soddisfare per lo sviluppo dell'interfaccia abbiamo proposto
alcune valide soluzioni al problema, tra le quali è stata scelta per semplicità d'uso e di implementazione quella della creazione di una piccola toolbar posizionata sullo schermo vicino alla pentray
della lavagna.
Lo sviluppo dell'interfaccia non può di per se rappresentare una soluzione ed un esempio, poiché la
toolbar creata deve essere associata ad un programma interattivo che ne faccia uso. È stato quindi
scelto come caso d'uso l'adattamento del menù di penna ad un simulatore di fisica bidimensionale.
Per poter fare ciò però abbiamo analizzato i pacchetti open source a disposizione, valutandone per
ognuno l'espandibilità e la possibilità di utilizzarlo in concomitanza con la toolbar in oggetto.
La soluzione proposta è stata quindi analizzata attraverso il codice sviluppato. La toolbar, o menù di
penna, è stata creata in modo da rappresentare un modulo applicabile a diversi casi, mettendo a
disposizione degli sviluppatori un'interfaccia facilmente utilizzabile.
Un altro fattore su cui è stata posta particolare attenzione è stato quello riguardante la cattura degli
eventi generati attraverso la lavagna. È stato mostrato il metodo per interpretare correttamente gli
input ricevuti attraverso le API della lavagna interattiva multimediale, analizzando le tecniche per
65
permettere all'utente l'esecuzione di azioni personalizzate in base allo strumento della lavagna ed
all'oggetto scelto all'interno della toolbar creata.
Infine è stato mostrato un caso in cui si sia fatto uso dell'interfaccia proposta. SmartBox2D
rappresenta di fatto un'applicazione ad alto tasso di interattività che permette l'utilizzo degli
strumenti messi a disposizione della lavagna per simulare un ambiente a due dimensioni che rispetta
le leggi della fisica. Sono stati mostrati i metodi utilizzati per interfacciare gli input e la toolbar
all'output mostrato attraverso il motore fisico.
Si può quindi notare come l'interfaccia sviluppata attraverso il linguaggio Java, permette l'utilizzo
della stessa in contesti differenti in maniera poco invasiva e facile da comprendere per l'utente che
ne fa uso.
Il caso posto in questa sede può avere degli sviluppi futuri, tra i quali ci sono quelli di veloce e
semplice creazione come l'aggiunta di altre forme da inserire nel sistema, la possibilità di disegnare
il perimetro dell'oggetto da creare.
Nel programma da noi sviluppato abbiamo scelto le texture staticamente, ma è possibile in futuro
implementare la possibilità di scegliere la texture da applicare ad ogni oggetto senza dover cambiare
radicalmente il programma. In tal caso risulterebbe di più semplice comprensione la simulazione di
un numero elevato di elementi. Altre funzioni possono essere aggiunte ed implementate all'interno
di SmartBox2D, ma la soluzione proposta presenta di per se una valida soluzione ed un esempio
esplicativo della flessibilità dell'interfaccia proposta.
66
Bibliografia
<1> Painter, D Whiting, E and Wolters, B , ( 2005 ) "The Use of an Interactive Whiteboard in promoting
interactive teaching and learning"
<2> British Educational Communications and Technology Agency , Coventry, U.K. ( 2003 ) "What
Research Says About Interactive Whiteboard" <
http://web.archive.org/web/20061208064641/http://www.becta.org.uk/page_documents/research/wtrs_white
boards.pdf >
<3> SMART Technologies , ( ) "In wall rear projection System" : <
http://www.wedgwoodav.com/Download.aspx?ProductRef=Q6CSE4959 >
<4> Numonics Corp. , ( ) "Electromagnetic Technologyand Its Advantages in Interactive Products" : <
www.interactivewhiteboards.com/www/files/techdocs/electromagnetic_whatisit.pdf >
<5> Johnny Chung Lee , ( 2007 ) "Projects - Wii Remote Interactive Smartboard" : <
http://www.cs.cmu.edu/%7Ejohnny/projects/wii/ >
<6> SMART Technologies , ( ) "DViT Technology (Digital Vision Touch)" : < http://smarttech.com/dvit/
index.asp >
<7> Bobsguide , ( 2003 ) "SMART Technologies Inc. invents new technology for touch-sensitive
displays" : <
http://www.bobsguide.com/guide/news/2003/May/23/SMART_Technologies_Inc._invents_new_technology
_for_touch-sensitive_displays.html >
<8> Beauchamp, G and Parkinson, J , ( 2005 ) "Beyond the wow factor: developing interactivity with the
interactive whiteboard"
<9> Dane Nourie , ( ) "Dane Nourie's Blog: Handwriting Recognition with Java Technology" : < http://
weblogs.java.net/blog/dnourie/archive/2006/05/handwriting_rec.html >
<10> Wikipedia, the free encyclopedia , ( ) "Hidden Markov model" : <
http://en.wikipedia.org/wiki/Hidden_Markov_model >
<11> Wikipedia, the free encyclopedia , ( ) "Viterbi Algorithm" : <
http://en.wikipedia.org/wiki/Viterbi_algorithm >
<12> Diana Negoescu , ( ) "Handwriting Recognition: Project Description" : <
http://www.cs.princeton.edu/academics/ugradpgm/spe/summer06/negoescu/ >
<13> Andrew Witkin and David Baraff , Los Angeles ( Agosto 1997 ) "Physically Based Modeling:
Principles and Practice" : Association for Computing Machinery Special Interest Group on Graphics <
http://www.cs.cmu.edu/~baraff/sigcourse/ >
<14> Chris Baker , ( Marzo 2008 ) "Crayon Physics Deluxe, an ingenious video game that looks like it was
designed by a third-grader" : Slate < http://www.slate.com/id/2186848/ >
<15> "Phun research project at VRlab, Umeå University" : < http://www.vrlab.umu.se/research/phun/ >
67
Scarica

Lavagne Interattive Multimediali - Marco Ronchetti