Alma Mater Studiorum · Università di Bologna
SCUOLA DI SCIENZE
Corso di Laurea in Informatica per il Management
FOG ESCAPING:
Un’applicazione di mobile data Crowd-Sourcing
per il supporto alla mobilità veicolare
Tesi di Laurea in Basi di Dati e Sistemi Informativi
Relatore:
Chiar.mo Prof.
MARCO DI FELICE
Presentata da:
FEDERICO MACCAFERRI
Sessione III
Anno Accademico 2012-2013
Part of the inhumanity of the computer is that,
once it is competently programmed and working smoothly,
it is completely honest. . .
I.Asimov
Indice
1 Introduzione
1
2 Stato dell’Arte
3
2.1
2.2
Participatory Sensing . . . . . . . . . . . . . . . . . . . . . . .
3
2.1.1
Vantaggi . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2.1.2
Problematiche . . . . . . . . . . . . . . . . . . . . . . .
4
Participatory Sensing Application . . . . . . . . . . . . . . . .
7
2.2.1
Applicazioni Incentrate sulle Persone . . . . . . . . . .
7
2.2.2
Applicazioni Incentrate sull’Ambiente . . . . . . . . . . 11
2.2.3
Applicazioni Miste . . . . . . . . . . . . . . . . . . . . 15
3 Problema Affrontato e Metodologia Utilizzata
19
3.1
Segnalazione della Visibilità . . . . . . . . . . . . . . . . . . . 19
3.2
Ricerca Percorso Alternativo . . . . . . . . . . . . . . . . . . . 20
3.2.1
Richiesta Percorso Ottimale . . . . . . . . . . . . . . . 20
3.2.2
Griglia dei Punti: Costruzione di un Grafo . . . . . . . 20
3.3
Richiesta dei Dati Ambientali . . . . . . . . . . . . . . . . . . 23
3.4
Ricerca nel Grafo : Dijskra . . . . . . . . . . . . . . . . . . . . 24
3.5
Correzione della Soluzione . . . . . . . . . . . . . . . . . . . . 26
3.6
Correzione del Percorso . . . . . . . . . . . . . . . . . . . . . . 28
3.7
Struttura del Sistema . . . . . . . . . . . . . . . . . . . . . . . 29
4 Implementazione
4.1
31
Architettura del Sistema . . . . . . . . . . . . . . . . . . . . . 31
3
INDICE
4.2
4.3
INDICE
4.1.1
Client . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.1.2
Server . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.3
Protocollo di Comunicazione . . . . . . . . . . . . . . . 33
Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.2.1
Implementazione Stored Procedure . . . . . . . . . . . 42
4.2.2
Implementazione PHP . . . . . . . . . . . . . . . . . . 46
Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.3.1
Notification . . . . . . . . . . . . . . . . . . . . . . . . 59
4.3.2
RoutePlanningViewController . . . . . . . . . . . . . . 59
4.3.3
LoginViewController . . . . . . . . . . . . . . . . . . . 66
4.3.4
RegistrationViewController . . . . . . . . . . . . . . . . 68
4.3.5
registrationError: . . . . . . . . . . . . . . . . . . . . . 71
4.3.6
FogGeoTagViewController . . . . . . . . . . . . . . . . 72
4.3.7
EscapeFromFogViewController
4.3.8
Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.3.9
insertAllGridIntoDijskraAlgorithm . . . . . . . . . . . 81
. . . . . . . . . . . . . 73
4.3.10 FogRequest . . . . . . . . . . . . . . . . . . . . . . . . 82
4.3.11 CustomAnnotationPoint . . . . . . . . . . . . . . . . . 87
4.3.12 ControlPoint . . . . . . . . . . . . . . . . . . . . . . . 87
4.3.13 Routepoint . . . . . . . . . . . . . . . . . . . . . . . . 88
4.3.14 AlternativeRouteSegment . . . . . . . . . . . . . . . . 89
4.3.15 PESGraph . . . . . . . . . . . . . . . . . . . . . . . . . 90
5 Studi sull’Image Recognition
93
5.1
OpenCV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.2
Object Recognition . . . . . . . . . . . . . . . . . . . . . . . . 94
5.3
Image Analyzer . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6 Validazione
6.1
101
Prestazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.1.1
Utilizzo di Memoria . . . . . . . . . . . . . . . . . . . . 101
6.1.2
Utilizzo CPU . . . . . . . . . . . . . . . . . . . . . . . 102
INDICE
6.2
6.3
5
6.1.3
Consumo di Energia . . . . . . . . . . . . . . . . . . . 103
6.1.4
Timeline di Esecuzione . . . . . . . . . . . . . . . . . . 104
Comparazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
6.2.1
Comparazione con Waze . . . . . . . . . . . . . . . . . 106
6.2.2
Comparazione con OpenSignal . . . . . . . . . . . . . . 107
6.2.3
Comparazione con Weendy . . . . . . . . . . . . . . . . 108
ScreenShot di Fog Escaping . . . . . . . . . . . . . . . . . . . 110
6.3.1
Stato Iniziale . . . . . . . . . . . . . . . . . . . . . . . 110
6.3.2
Registrazione . . . . . . . . . . . . . . . . . . . . . . . 111
6.3.3
Login . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.3.4
Segnalazione Nebbia . . . . . . . . . . . . . . . . . . . 113
6.3.5
Ricerca Percorso Alternativo . . . . . . . . . . . . . . . 114
Conclusioni
115
Riepilogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Difficoltà emerse . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Implementazioni Future dell’Algoritmo . . . . . . . . . . . . . . . . 116
Estensioni Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Epilogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Bibliografia
119
Elenco delle figure
2.1
EveryTrail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2
PlugShare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3
Weendy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.4
INRIX Traffic . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5
OpenSignal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.6
Waze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1
Inserimento dei quattro margini esterni. . . . . . . . . . . . . . 21
3.2
Inserimento dei Punti di Controllo. . . . . . . . . . . . . . . . 22
3.3
Processo di sostituzione con i punti di Partenza e Arrivo . . . 23
3.4
Valutazione del parametro di visibilità. . . . . . . . . . . . . . 24
3.5
Punti di controllo sulla griglia. . . . . . . . . . . . . . . . . . . 25
3.6
Allontanamento parziale dalla meta.
3.7
Comparazione delle direzioni, prima e dopo la correzione . . . 27
3.8
Esempio di inversione. . . . . . . . . . . . . . . . . . . . . . . 29
3.9
Il Sistema Fog Escaping. . . . . . . . . . . . . . . . . . . . . . 29
4.1
Diagramma di Sequenza: Registrazione Utente. . . . . . . . . 34
4.2
Diagramma di Sequenza: Login Utente. . . . . . . . . . . . . . 36
4.3
Diagramma di Sequenza: Invio Segnalazione. . . . . . . . . . . 38
4.4
Invio Griglia di Punti di Controllo
4.5
Pattern Model-View-Controller. . . . . . . . . . . . . . . . . . 57
4.6
Storyboard iPhone. . . . . . . . . . . . . . . . . . . . . . . . . 58
4.7
Storyboard iPad. . . . . . . . . . . . . . . . . . . . . . . . . . 59
7
. . . . . . . . . . . . . . 26
. . . . . . . . . . . . . . . 40
8
ELENCO DELLE FIGURE
5.1
Test di Riconoscimento Oggetti. . . . . . . . . . . . . . . . . . 95
5.2
Test di Comparazione Immagini.
6.1
Timeline dell’Utilizzo di Memoria. . . . . . . . . . . . . . . . . 102
6.2
Test di Utilizzo CPU su iPhone. . . . . . . . . . . . . . . . . . 102
6.3
Timeline di Vita dei Thread. . . . . . . . . . . . . . . . . . . . 103
6.4
Paragone del Consumo Energetico tra Rete Wifi e Cellulare. . 104
6.5
Test prestazioni su iPhone con rete wifi. . . . . . . . . . . . . 105
6.6
Comparazione con Instrument. . . . . . . . . . . . . . . . . . . 106
6.7
Utilizzo CPU di Waze. . . . . . . . . . . . . . . . . . . . . . . 107
6.8
Utilizzo CPU di OpenSignal. . . . . . . . . . . . . . . . . . . . 108
6.9
Utilizzo CPU di Weendy. . . . . . . . . . . . . . . . . . . . . . 109
. . . . . . . . . . . . . . . . 100
6.10 Icona di Fog Escaping. . . . . . . . . . . . . . . . . . . . . . . 110
6.11 Stato di primo avvio dell’applicazione Fog Escaping . . . . . . 110
6.12 Processo di Registrazione. . . . . . . . . . . . . . . . . . . . . 111
6.13 Errore di Registrazione. . . . . . . . . . . . . . . . . . . . . . 111
6.14 Processo di Login. . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.15 Errore di Login. . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.16 Processo di Segnalazione tramite iPhone. . . . . . . . . . . . . 113
6.17 Processo di Segnalazione tramite iPad. . . . . . . . . . . . . . 113
6.18 Ricerca Percorso Alternativo su iPhone.
. . . . . . . . . . . . 114
6.19 Ricerca Percorso Alternativo su iPad. . . . . . . . . . . . . . . 114
Capitolo 1
Introduzione
È chiaro oramai, come sia quasi impossibile nel terzo millennio, vivere lontano dai nostri smartphone, perché rappresentano in ogni momento, il punto
d’unione tra noi, la nostra vita privata, quella intima, sociale e culturale o
lavorativa che sia. Alcuni paradigmi che stanno evolvendo come il Participatory Sensing e il Data Crowd-Sourcing, possono rendere questi device sempre
più utili. I progressi tecnologici che in continuazione migliorano gli smartphone, hanno spianato le strade a un nuovo paradigma per i rilevamenti su
larga scala, conosciuto come Participatory Sensing. L’idea dietro il Participatory Sensing è di sensibilizzare e responsabilizzare i cittadini, in modo che
essi possano raccogliere dati dagli ambienti circostanti e renderli disponibili
alla collettività. È possibile quindi creare una rete dove il cittadino stesso
crea i contenuti utili che saranno utilizzati per la soddisfazione di un bisogno collettivo. I telefoni cellulari, anche se non costruiti appositamente per
il rilevamento, sono muniti di svariati sensori che possono essere utilizzati
per raccogliere dati dall’ambiente e che quindi aprono agli sviluppatori, un
mondo di possibili e plausibili innovazioni tecnologiche.
Gli smartphone diventano sempre più intelligenti grazie all’utilizzo di nuove tecnologie integrate o nella rete. Iniziano a capire alcuni pattern della
nostra vita, imparano il nostro stato di salute e ci aiutano durante la giornata. Gli smartphone diventeranno sempre più cognitivi [1]. Nel futuro sarà
1
2
1. Introduzione
sempre più indispensabile che gli smartphone conoscano e prevedano i modi in cui gli utenti utilizzano le applicazioni. La previsione di utilizzo delle
applicazioni potrebbe dare benefici come il pre-caricamento, riducendo drasticamente i tempi di apertura, rendendoli quasi istantanei [2].
L’idea alla base di questa Tesi di laurea è creare un’applicazione semplice, intuitiva e rapida che permetta di risolvere un problema molto sentito nel
nostro territorio: La circolazione in caso di scarsa visibilità per colpa delle
nebbie. Questa problematica è stata sollevata dal Responsabile dell’Area di
Progettazione Sistemi Informativi, il Sig.Cattani Stefano di ARPA (Agenzia
Regionale Per l’Ambiente)
In questa Tesi si affrontano tutte le idee e i passaggi che hanno permesso la
creazione dell’applicazione Fog Escaping. Nel secondo capitolo sono analizzati i paradigmi di Data Crowd-Sourcing e Participatory Sensing, mostrando
una panoramica delle Applicazioni esistenti. Nel terzo capitolo è descritto il
problema riguardante lo sviluppo dell’applicazione Fog Escaping, attraverso
i ragionamenti che hanno portato alla sua realizzazione. Nel quarto capitolo
è descritta l’implementazione del Sistema; sono specificati i dettagli implementativi riguardanti il Server, il Database e il Client. Nel quinto capitolo
sono descritti gli studi effetuati sulla Image Recognition; sono specificati i
dettagli implementativi riguardanti il riconoscimento di oggetti in movimento e i metodi di analisi delle immagini. Nel sesto capitolo sono analizzate
le prestazioni dell’applicazione, confrontandola con altre simili; sono inoltre
presenti alcuni screenshot dell’applicazione Fog Escaping in esecuzione. Nel
settimo e ultimo capitolo è presente un riepilogo del lavoro realizzato e una
discussione critica sulle difficoltà riscontrate e sulle possibili implementazioni
future.
Capitolo 2
Stato dell’Arte
In questo capitolo s’introduce il paradigma di Participatory Sensing; ovvero la
raccolta di dati dalle persone che possiedono dispositivi mobili (Data CrowdSourcing). Si discuteranno i vantaggi, gli svantaggi e si farà una panoramica
sulle tegnologie attualmente sviluppate.
2.1
Participatory Sensing
La crescente presenza della connettività internet e di potenti sensori sui nostri
device mobili, ha aperto le porte a un nuovo paradigma per il monitoraggio
del territorio conosciuto come Participatory Sensing [3], [4]. Più di 5 bilioni
di persone in tutto il mondo hanno accesso ai telefoni cellulari. I progressi
raggiunti nel campo delle tecnologie mobili, e la loro ubiquità, hanno permesso la rilevazione dei dati su larga scala. L’idea dietro al Participatory Sensing
si basa sul concetto della raccolta e della condivisione dei dati negli ambienti
circostanti da parte dei cittadini attraverso i dispositivi mobili. I telefoni
cellulari non sono stati creati per specifiche rilevazioni, ma possiedono una
serie di sensori che se utilizzati nella maniera corretta possono generare dati
affidabili.
3
4
2. Stato dell’Arte
2.1.1
Vantaggi
Sono molti i vantaggi derivanti dai sistemi di rilevazione cooperativa. Innanzitutto si utilizzerebbero rilevatori già esistenti (i telefoni cellulari). La
comunicazione può essere fatta tramite la rete Wifi o Cellulare; quindi i costi
d’installazione sono virtualmente zero. Come secondo vantaggio si ha una
copertura spaziotemporale che non ha precedenti; questo tipo di copertura
sarebbe capace di rilevare eventi altrimenti impossibili da riscontrare (come
l’inquinamento localizzato). Come terzo vantaggio si hanno le economie di
scala dovute dall’utilizzo dei cellulari invece di sofisticati sensori. Come ultimo, ma non meno importante, abbiamo la presenza di sistemi di sviluppo e
di reti di distribuzione che permettono una pubblicazione veloce e semplice
delle applicazioni.
2.1.2
Problematiche
Invio di Dati Incompleti
La raccolta dei dati arriva direttamente dalle persone che contribuiscono alle
rilevazioni; questo limita la misurazione ai soli posti in cui queste persone
sono presenti. Inoltre è possibile che gli utenti vogliano preservare l’uso del
dispositivo mobile per altre applicazioni, o potrebbero scegliere di raccogliere
dati solo quando hanno sufficiente energia. Questi dati essendo tipicamente
distribuiti randomicamente nello spazio e nel tempo, sono incompleti. è quindi un obiettivo importante riuscire ad utilizzare tecniche capaci di analizzare
questi dati e trarne conclusioni affidabili [5].
Dedurre Contenuti e Attività dell’Utente
è importante che i dispositivi mobili diventino sempre più cognitivi [1], e che
comprendano e apprendano le tipologie di attività svolte da un utente in un
determinato momento. Sono quindi necessarie tecniche di machine learning
che raccolgano una mole di dati dai sensori e ne ricavino una serie di attività
[6].
2.1 Participatory Sensing
Preservare la Privacy dell’utente
I dati nel Participatory Sensing sono raccolti su larga scala, è quindi necessario che siano protetti, evitando intrusioni nella privacy dell’utente. Finché
i dati saranno raccolti direttamente dagli utenti, si avrà una certa riluttanza
da parte delle persone. Il rischio è che questi dispositivi si trasformino in
microspie poiché possono conoscere se siamo svegli, dove siamo, se stiamo
facendo una conversazione e con chi. Sono quindi state studiate applicazioni
capaci di prelevare i dati in modo anonimo tramite la rilevazione opportunistica [7], dove non è il dispositivo a inviare autonomamente i dati ma è
utilizzata una strategia di delegazione per la raccolta.
Valutare l’Affidabilità dei dati
è molto importante che si raccolgano dati su larga scala; purtroppo è possibile
che ci siano persone che non collaborano correttamente, inviando dati non
affidabili o errati. è quindi una sfida importante riuscire a capire chi sta
inviando dati corretti e chi no. Sono quindi stati proposti alcuni sistemi di
reputazione [8], dove gli utenti hanno un punteggio che riflette l’affidabilità
dei dati che hanno inviato e quelli ancora da inoltrare.
Risparmio Energetico
Gli utenti si sentono realizzati nel contribuire alla raccolta dei dati solo se
questo non compromette notevolmente la durata della batteria del dispositivo. In questo momento i dispositivi mobili vengono ricaricati una volta al
giorno, questo però non deve essere un presupposto per un consumo maggiore
di energia. Al contrario è necessario che i dispositivi trattengano la carica a
lungo, affinché il processo di rilevazione dei dati sia il meno costoso possibile.
Alcuni sensori come il GPS, consumano molta più energia degli altri, ma la
necessità di sapere dove è localizzato l’utente ha permesso lo sviluppo del
Participatory Sensing. è quindi necessario utilizzare questi sensori in modo
conservativo. Sono stati studiati dei sistemi che permettono di passare dalla
5
6
2. Stato dell’Arte
rilevazione accurata ma costosa del GPS, alle rilevazioni meno accurate ma
più efficienti, tramite la localizzazione Wifi o tramite rete Cellulare [9].
Anche le piattaforme di sviluppo come XCode di Apple, permettono di
richiedere la posizione dell’utente nel modo più conservativo possibile, passando dalla rilevazione GPS, all’identificazione tramite vicinanza a una rete
Wifi, oppure alla triangolazione delle reti Cellulari. Ovviamente non tutte
le applicazioni possono utilizzare questa politica conservativa, infatti, quelle
di navigazione consumano molta energia per la necessità di utilizzo di dati
precisi provenienti dal GPS.
Stress delle Infrastrutture
La proliferazione dei dispositivi mobili ha reso disponibile la possibilità di
raccogliere dati su larga scala tramite il Crowd-Sourcing. Le soluzioni correnti, dipendendo dalla grandezza della folla, creano imprevedibili stress sulle
infrastrutture e la dipendenza di energia dei device può causare una rilevazione non accurata del comportamento delle persone [10]. Sono state considerate le Olimpiadi di Londra del 2012. Mentre era possibile prevedere la
frequentazione di un particolare evento, non c’era modo di prevedere come le
persone si muovessero, mettendo in stress molte risorse della città. CrowdWatch [10] è un sistema collaborativo basato sugli smartphone; esso permette
a servizi di monitoraggio e di feedback, di monitorare il comportamento e le
dinamiche delle persone all’interno della folla. Anche se Londra è nota per
il sistema di fotocamere, le informazioni raccolte con esso richiedono una
complessa e costosa elaborazione delle immagini [11] e quindi non può essere utilizzato per reagire agli eventi in tempo reale. Il Crowd-Sourcing [12]
e il Crowd-Computing [13][14] sono utilizzati per sfruttare le informazioni
raccolte dagli individui all’interno della folla, ma in momenti di emergenza
o sovraffollamento [15] l’accesso al server tramite la rete cellulare, potrebbe essere molto inaffidabile e quindi questi dati potrebbero non essere resi
disponibili ai server.
2.2 Participatory Sensing Application
CrowdWatch riesce a raggiungere l’efficienza energetica e un monitoraggio
di folla distribuito, sfruttando tre osservazioni fondamentali. In primo luogo
le folle tendono a concentrarsi in gruppi, pertanto non è necessario che tutti
gli utenti raccolgano dati in ogni momento. In secondo luogo considerando la
dinamicità delle affluenze, si è notato che evolvono in continuazione; pertanto
non è necessario avere un’istantanea perfetta della folla in ogni momento. In
terzo luogo, la maggior parte dei dispositivi mobili attuali possiedono più
sistemi radio come Wifi e Bluetooth.
CrowdWatch costruisce una gerarchia di dispositivi, sfruttando la lontananza Wifi per la creazione di una dorsale dinamica tra la folla e la connettività Bluetooth, per sostenere il campionamento e la raccolta dei dati.
Attualmente i ricercatori, sono in fase di progettazione di applicazioni che
utilizzeranno l’architettura CrowdWatch; esse permetteranno di studiare le
dinamiche di interazione interpersonale in una scala senza precedenti.
2.2
Participatory Sensing Application
Possiamo suddividere le tipologie di applicazioni di Participatory Sensing in
tre filoni: incentrate sulle persone (people-centric), incentrate sull’ambiente
(environment-centric) e miste. Le applicazioni incentrate sulle persone, si
focalizzano sulla documentazione di attività (viaggi, attività sportive) e sulla
comprensione del comportamento degli individui (disordini alimentari, diete).
Le applicazioni incentrate sull’ambiente, raccolgono informazioni e parametri
dall’ambiente circostante (qualità dell’aria, inquinamento acustico). Mentre
le applicazioni miste uniscono alcuni aspetti dalle due categorie precedenti.
In questa sezione sono presentate alcune applicazioni rappresentative per
ognuna delle due categorie.
2.2.1
Applicazioni Incentrate sulle Persone
Le applicazioni incentrate sulle persone, utilizzano i sensori integrati nei
dispositivi mobili, per la raccolta di informazioni che riguardano l’utente.
7
8
2. Stato dell’Arte
Monitoraggio dello Stato di Salute
Nel monitoraggio dello stato di salute, i dispositivi mobili sono utilizzati per
monitorare lo stato psicologico e di salute dei pazienti/partecipanti. I dispositivi utilizzano sensori integrati o esterni. (es. accelerometro indossabile, o
sensore d’inquinamento).
DietSense [16] assiste i partecipanti che vogliono perdere peso. Si monitorano i piatti dell’utente, sistemando il dispositivo mobile attorno al collo
dei partecipanti. Il dispositivo raccoglie automaticamente immagini riguardo
ai piatti che l’utente si appresta a mangiare. Le immagini raccolte permettono di estimare il peso del cibo e la parte non mangiata. Inoltre il dispositivo
mobile raccoglie informazioni riguardo al contesto del pasto registrando l’ora, le coordinate geografiche e i suoni registrati per dedurre relazioni fra i
partecipanti e il comportamento nel contesto. I dati sono inseriti in un archivio personale, dove l’utente può rivederli, selezionarli, eliminarli oppure
condividerli con i propri medici e nutrizionisti.
Bewell [17] è un’applicazione android che utilizza il modello BES [18]. Il
modello BES stima la durata del sonno dell’utente, sfruttando i dati di utilizzo del telefono e le statistiche raccolte dagli stessi utenti tramite Bewell.
In particolare, BES tiene traccia su base giornaliera, della durata complessiva di tempo, in cui il telefono è in uno di questi stati: bloccato, spento,
in carica, al buio o in un ambiente silenzioso. Tutti i dati necessari, sono
raccolti esclusivamente da sensori incorporati nel telefono, senza intervento
dell’utente. BES presume che vi sia un rapporto statistico, tra la durata del
sonno dell’utente e il periodo che il telefono rimane al buio. BES tenendo
conto di tutte le caratteristiche descritte in precedenza, dedurrà la durata del
sonno dell’utente. Esistono altre applicazioni per monitorare il sonno; esse
utilizzano sensori esterni, come ad esempio JawBone UP [19], che si serve di
un bracciale connesso al dispositivo tramite bluetooth.
2.2 Participatory Sensing Application
PEIR (Personal Environmental Impact Report) [20] è un sistema che permette agli utenti di utilizzare il proprio telefono cellulare, per determinare
l’esposizione agli agenti inquinanti nell’ambiente. Utilizzando le informazioni
sulla posizione dell’utente e sulle modalità di spostamento, il server fornisce
agli utenti le informazioni sull’impatto ambientale del loro viaggio, in termini di emissione di particelle e agenti inquinanti. Raccoglie inoltre dati
aggiuntivi, dalle stazioni metereologiche e dai servizi di traffico.
Monitoraggio delle attività sportive
BikeNet [21] è un sistema di monitoraggio degli utenti durante le attività
ciclistiche. Esso traccia il profilo di ogni ciclista, tramite la misurazione della
posizione e della risposta galvanica della pelle. Sono utilizzati una moltitudine di sensori per la raccolta di informazioni: microfono, magnetometro,
sensore di velocità della pedalata, inclinometro, lateral tilt, GSR stress monitor e sensori di concentrazione di anidride carbonica. I sensori periferici
comunicano tramite una connessione senza fili e i dati catturati possono essere rivisti, uniti con altri partecipanti o combinati con parametri addizionali
come la qualità dell’aria e le condizioni del traffico, in modo da poter costruire mappe per la comunità dei ciclisti.
Runtastic [22] è un’applicazione che monitora il percorso dell’utente e permette di salvare e condividere questi percorsi. è inoltre possibile incitare le
persone che stanno facendo attività sportiva. Runtastic può essere collegato
a sensori esterni per il monitoraggio del battito cardiaco.
RunKeeper [23] è un’applicazione che aiuta a monitorare un percorso, permette di scegliere dei piani di allenamento, e persino di “noleggiare” un
trainer.
RunKeeper è associabile al braccialetto di JawBone [19] per il
monitoraggio dei valori corporei.
9
10
2. Stato dell’Arte
Monitoraggio dei Viaggi
EveryTrail [24] è un’applicazione che permette all’utente di cercare o creare
guide per viaggi. Le guide create con quest’applicazione comprendono la
direzione precisa del viaggio e le foto che l’utente creatore ha deciso di scattare
durante la registrazione del percorso. è quindi possibile seguire un percorso,
visionando le foto e i commenti; alcuni percorsi sono paragonabili a vere e
proprie guide turistiche. EveryTrail utilizza un sistema di reputazione gestito
direttamente dagli utenti tramite il classico sistema a cinque stelle.
Figura 2.1: EveryTrail per iOS7
Miglioramento dei Social Media
Sono molte le applicazioni che utilizzano i dati acquisiti dai sensori per arricchire i contenuti che sono condivisi nei social. CenceMe [6] raccoglie informazioni dai dispositivi mobili (accelerazione, campioni audio, immagini, posizione), questi dati sono poi utilizzati per dedurre informazioni sull’attività
svolta in un determinato ambiente, sull’umore e le abitudini. L’informazione
dedotta è poi tradotta e condivisa come rappresentazione dei partecipanti
nel mondo virtuale.
Raccolta dei Prezzi
PetrolWatch [25] è un sistema che automatizza la raccolta dei prezzi, usando
le telecamere dei dispositivi mobili. Il dispositivo è montato nel seggiolino del
2.2 Participatory Sensing Application
passeggero e viene rivolto verso la strada, per fotografare automaticamente
i prezzi nei cartelli delle stazioni di rifornimento, quando il veicolo è nelle
vicinanze (GPS e GIS). L’immagine è inviata al server che la elabora tramite
algoritmi di computer vision, che estrapolano il prezzo. Gli utenti possono
quindi richiedere al database, quale sia il distributore più vicino con prezzo
inferiore.
Monitoraggio delle Stazioni di Ricarica
PlugShare [26] permette di cercare le stazioni di ricarica più vicine, permette
inoltre di impostare la tipologia di motore che si deve ricaricare, in modo
che possa essere cercata una stazione adeguata. Gli utenti possono anche
aggiungere stazioni di ricarica sia pubbliche sia private (nelle abitazioni).
PlugShare notifica l’utente, non solo della presenza delle stazioni, ma anche
della loro disponibilità.
Figura 2.2: PlugShare per iOS7
2.2.2
Applicazioni Incentrate sull’Ambiente
Negli scenari incentrati sull’ambiente, i dispositivi mobili catturano le informazioni tramite sensori integrati e sensori esterni per l’analisi dell’ambiente
circostante. A differenza dello scenario incentrato sulle persone, i dati acquisiti sono utilizzati principalmente su scala comunitaria, ad esempio per
11
12
2. Stato dell’Arte
monitorare alcuni parametri ambientali come la qualità dell’aria, l’inquinamento acustico, le condizioni di traffico o per rilevare eventi socialmente
interessanti.
Monitoraggio Qualità dell’Aria
HazeWatch [27] è un’applicazione dove i dispositivi mobili sono collegati con
sensori d’inquinamento esterni per misurare la concentrazione del monossido
di carbonio, ozono, diossido di zolfo e diossido di azoto nell’aria. Comparati
alle stazioni metereologiche, i dispositivi mobili possono raccogliere dati meno accurati; è però possibile raccogliere dati inaspettati come l’inquinamento
accidentale. I dati sono salvati insieme al timestamp e alla geo-localizzazione,
sono poi aggregati con dati affidabili (stazioni metereologiche) e resi disponibili a tutti gli utenti.
Air Quality Egg [28] è principalmente una comunità che condivide la passione per il rilevamento degli agenti inquinanti. Ognuno degli utenti possiede
un insieme di sensori a forma di uovo che connesso a internet, invia i dati
direttamente alla comunità. Nonostante non siano molti i dispositivi attualmente connessi, l’idea è certamente interessante perché se si riuscisse ad
attivare il mondo delle persone interessate, si potrebbero unire i dati rilevati
dalle stazioni adibite a quelli provenienti dagli utenti affidabili.
Monitoraggio dati Ambientali
Weendy [29] è un’applicazione che permette agli utenti, di notificare le condizioni del vento nella zona in cui si trovano. è utilizzata principalmente da
chi pratica sport estremi come windsurf e surf; la comunità è molto presente
anche in Italia.
2.2 Participatory Sensing Application
Figura 2.3: Weendy per iOS7
La cosa che rende quest’applicazione affidabile, è il collegamento con alcune stazioni di rilevazione; si unisce quindi l’affidabilità all’ubiquità. Weendy
utilizza un sistema di reputazione gestito direttamente dagli iscritti; se un
utente notifica una buona condizione di vento per fare attività sportiva, gli
altri possono decidere di votare questa segnalazione e far guadagnare punti
a quell’utente. Inoltre è possibile seguire un determinato utente, in questo
modo a ogni sua segnalazione di vento si verrà notificati.
Monitoraggio del Rumore
I microfoni all’interno dei dispositivi mobili, permettono di monitorare il
livello di rumore e raccogliere informazioni sull’ambiente.
EarPhone [5], utilizza i microfoni per monitorare l’inquinamento acustico
che può influenzare le capacità di ascolto e il comportamento. è creata una
mappa, resa successivamente accessibile agli specialisti per capire le relazioni
fra l’esposizione al rumore e i problemi comportamentali delle persone.
13
14
2. Stato dell’Arte
Monitoraggio della Strada e delle Condizioni di Traffico
Figura 2.4: INRIX Traffic per iOS7
I dispositivi mobili possono essere utilizzati, per analizzare i problemi della
strada e del traffico.
Nericell [30] utilizza i sensori integrati come accelerometro, microfono e sistemi di posizionamento (GPS, GSM, Wifi) per analizzare e localizzare le condizioni del traffico e del manto stradale. L’applicazione integra le informazioni
di traffico, della superfice stradale e del rumore, per renderle disponibili alle
persone.
INRIX Traffic [31] è un’applicazione che unisce l’affidabilità delle rilevazioni
effettuate con telecamere per il monitoraggio della viabilità, alle segnalazioni inviate direttamente dagli utenti. Gli utenti che utilizzano INRIX per
navigare o per programmare una partenza, aiutano la comunità a evitare
condizioni di traffico insostenibili. INRIX utilizza un algoritmo dinamico che
muta insieme alle condizioni del traffico. Con INRIX è possibile segnalare
un disagio nelle condizioni di traffico come un incidente, un pericolo, dei lavori in corso oppure un colore di traffico errato in base alla reale condizione.
INRIX utilizza un sistema di reputazione, dove si guadagnano punti quando
le segnalazioni sono confermate da altri utenti della comunità.
2.2 Participatory Sensing Application
15
Monitoraggio delle Reti
OpenSignal [32] è un’applicazione che permette di visualizzare i dati di ricezione della rete cellulare. Contiene i dati sulla posizione delle celle, e in
background rileva i dati di ricezione direttamente dall’applicazione, senza
avvalersi dell’utente. I dati sono abbastanza aggiornati e realistici, è però
possibile notare che la maggior parte delle informazioni arriva dalle strade; questo fa pensare che il sistema utilizzi anche altri sistemi di rilevazione
(Figura 2.5b).
(a)
(b)
Figura 2.5: OpenSignal per iOS7.
2.2.3
Applicazioni Miste
è stato necessario creare una terza sezione per quest’applicazione che include
funzionalità incentrate sia sull’ambiente sia sulle persone.
Waze [33] è un applicazione di navigazione stradale dove gli utenti si scambiano informazioni. Gli utenti possono inviare dei report specifici sulla condizione della navigazione stradale: Traffico, Polizia, Incidente, Pericolo sulla
strada, Autovelox, Prezzi del Carburante, Chiusura di una strada e messaggi di chat per gli altri utenti. L’applicazione è multipiattaforma e ben
ottimizzata (Cap. 6.2.1).
16
2. Stato dell’Arte
(a)
(b)
Figura 2.6: Waze per iOS7.
L’utente si può registrare tramite Facebook, può vedere gli amici connessi
e in alternativa può invitarli. Una volta registrato al Sistema, l’utente è rappresentato dal suo Waze: una sorta di avatar a forma di automobile stilizzata
(Figura 2.6a). L’utente appena registrato è limitato in alcune opzioni, come
ad esempio l’invio di un report sui prezzi del carburante. Il proprio Waze,
in altre parole ciò che siamo all’interno l’applicazione, cresce man mano che
l’utente naviga e così facendo si sbloccano funzionalità.
Waze non è solo un applicazione, ma un vero e proprio Sistema, accedibile
anche tramite computer. Tramite L’Editor Web è possibile fare modifiche
alle mappe, limitando l’utente alle zone dove ha guidato. L’editor permette
di inserire una strada, una rotonda, un parcheggio, una stazione di servizio
o un generico landmark.
Quindi riassumendo Waze è: un social, è un modo per evitare il traffico ed è
anche un modo per segnalare una serie di informazioni che sono prettamente
incentrate sulle persone.
2.2 Participatory Sensing Application
17
Tabella 2.1: Tabella Riepilogativa delle Applicazioni
NOME
TIPOLOGIA
DietSense [16]
P
Bewell [17]
P
JawBone UP [19]
P
DESCRIZIONE
Permette agli utenti interessati al dimagrimento, di monitorare le
calorie dei propri piatti.
Stima la durata del sonno degli utenti.
https://bewellapp.org/
Utilizza un braccialetto per monitorare il battito cardiaco dell’utente;
può stimare la durata del sonno.
https://jawbone.com/up
PEIR [20]
P
BikeNet [21]
P
Determina l’esposizione degli utenti agli agenti inquinanti nell’ambiente.
Utilizza sensori integrati e esterni, per il monitoraggio degli utenti
durante le attività ciclistiche.
http://www.tacx.com/en/experience/bikenet
Runtastic [22]
P
Monitora il percorso dell’utente durante le attività fisiche. Può essere
associata a sensori esterni.
https://www.runtastic.com/it/
RunKeeper [23]
P
Monitora il percorso dell’utente e aiuta durante le sessioni di
allenamento, tramite i consigli di trainer specializzati.
http://runkeeper.com/
EveryTrail [24]
P
Permette di creare guide per viaggi e renderle accessibili agli altri
utenti della comunità.
http://it.everytrail.com/
CenceMe [6]
P
Raccoglie informazioni dai dispositivi mobili e li analizza per dedurre
le attività degli utenti.
http://metrosense.cs.dartmouth.edu/
PetrolWatch [25]
P
PlugShare [26]
P
HazeWatch [27]
A
Automatizza la raccolta dei prezzi tramite la fotocamera dei
dispositivi.
Ricerca le stazioni di ricarica per le autovetture con motore elettrico.
http://www.plugshare.com/
Raccoglie informazioni sugli agenti inquinanti utilizzando sensori
esterni.
http://www.pollution.ee.unsw.edu.au/
Air Quality Egg [28]
A
Rileva la qualità dell’aria tramite un dispositivo a forma di uovo
contenente sensori.
http://airqualityegg.com/
Weendy [29]
A
Permette di ricevere e inserire notifiche riguardanti le condizioni di
vento.
http://www.weendy.com/
EarPhone [5]
A
Nericell [30]
A
Rileva il livello di rumore tramite il microfono integrato del
dispositivo.
Analizza le condizioni del manto stradale e del traffico, utilizzando i
sensori interni del dispositivo.
http://research.microsoft.com/en-us/projects/nericell/
INRIX Traffic [31]
A
Permette di evitare il traffico stradale; utilizza i dati provenienti dalle
telecamere per il monitoraggio della viabilità e le segnalazioni ricevute
dagli utenti.
http://www.inrixtraffic.com/
OpenSignal [32]
A
Waze [33]
M
Permette di visualizzare i dati di ricezione della rete cellulare.
http://opensignal.com/
è un applicazione di navigazione stradale dove gli utenti si scambiano
informazioni riguardanti la viabilità.
https://www.waze.com/it/
P (Incentrata sulle Persone) - A (Incentrata sull’Ambiente) - M (Mista)
Capitolo 3
Problema Affrontato e
Metodologia Utilizzata
Questo capitolo si pone come obiettivo, la presentazione dei problemi e delle
soluzioni che sono state utilizzate per lo sviluppo del Sistema.
Si voleva realizzare un Sistema di monitoraggio della situazione delle
nebbie, che offrisse agli Utenti le seguenti funzionalità:
• Segnalazione dello stato di Nebbia tramite Geo-Tag;
• Creazione di un percorso alternativo.
3.1
Segnalazione della Visibilità
L’Utente deve poter scegliere uno stato di visibilità da segnalare; successivamente l’applicazione si occupa di richiedere al device la posizione; in caso
di successo il dato di posizione e il dato ambientale di nebbia sono inviati al
server. Il Client in seguito attende la risposta dal Server e ne comunica il
responso all’Utente.
19
20
3. Problema Affrontato e Metodologia Utilizzata
3.2
Ricerca Percorso Alternativo
L’Utente sceglie una posizione di partenza, che può essere l’attuale e una
posizione di arrivo. Il Client richiederà lo stato delle nebbie in una zona
limitata e dopo aver ricevuto questi dati dal Server, li analizzerà per generare
un percorso alternativo.
La ricerca di un percorso alternativo è in realtà un macro problema. Per
trovare un buon percorso alternativo, è stato utilizzato un approccio Greedy;
sono quindi utilizzate alcune soluzioni approssimate.
3.2.1
Richiesta Percorso Ottimale
Il Client innanzitutto richiede il percorso ottimale direttamente tramite l’oggetto MKDirections, che fornisce indicazioni stradali dai server di Apple. È
possibile utilizzare le istanze di questa classe per ottenere informazioni di
viaggio in termini di tempo o di direzione. L’oggetto passa poi la richiesta
ai server Apple e restituisce in modo asincrono le informazioni richieste in
oggetti chiamati directions.
3.2.2
Griglia dei Punti: Costruzione di un Grafo
Una volta che la direzione ottimale è stata calcolata, è necessario creare una
griglia di punti, che ci permetta in seguito di calcolare il percorso alternativo.
Immaginiamo la superficie della mappa come a uno spazio in due coordinate
x e y, che rappresentano rispettivamente longitudine e latitudine; è necessario
avere dei riferimenti nello spazio che ci permettano di trovare un cammino
per evitare le nebbie. Purtroppo non abbiamo un grafo completo di tutte le direzioni esistenti nello spazio reale (Mappa), quindi l’idea è di creare
una griglia con punti equidistanti fra loro. In una prospettiva di risparmio
di risorse, questa griglia non può essere infinitamente grande, ma deve essere delimitata da alcuni punti che comprendano il percorso che è stato in
precedenza calcolato (percorso ottimale).
3.2 Ricerca Percorso Alternativo
Figura 3.1: Inserimento dei quattro margini esterni.
A questo punto si creano quattro punti nello spazio delle coordinate latitudine e longitudine, che rappresentano gli estremi superiori e inferiori di un
rettangolo che farà da contenitore per la griglia dei punti (Figura 3.1). Sulla
base dei quattro punti sul piano, è creato uno strato di punti a intervalli
regolari, che ricopre tutto il rettangolo. (Figura 3.2).
Un Punto di Controllo è un punto geo-localizzato al quale è associato un
valore di riga e di colonna, in modo da essere riconoscibile sia come punto
nello spazio, sia come elemento di una griglia. Un Punto di Controllo, ha
determinate proprietà di adiacenza con altri Punti di Controllo.
Quest’astrazione permette di separare il concetto di richiesta del dato ambientale per un determinato punto geografico, dal concetto di grafo costruito
tramite la griglia.
21
22
3. Problema Affrontato e Metodologia Utilizzata
Figura 3.2: Inserimento dei Punti di Controllo.
Questo processo non è privo di vizi, infatti, i punti della griglia non corrispondono quasi mai a punti appartenenti a una strada e nemmeno ai punti
di partenza e arrivo che sono stati inseriti. Il primo problema è risolto con
la correzione del percorso (Cap. 3.6) mentre il secondo problema è risolto
inserendo i punti di partenza e arrivo, tramite un processo di sostituzione
per vicinanza a uno degli altri punti appartenenti alla griglia.
A questo punto abbiamo costruito il nostro grafo di Punti di Controllo ,
con il quale sarà generata una richiesta al Server.
3.3 Richiesta dei Dati Ambientali
Figura 3.3: Processo di sostituzione con i punti di Partenza e Arrivo
3.3
Richiesta dei Dati Ambientali
In questa fase il Server riceve una richiesta di dati ambientali, contenente
tutti i punti della griglia; per ognuno di questi punti interroga il Database
circa l’esistenza di segnalazioni di visibilità nelle vicinanze. Il parametro di
vicinanza è a discrezione del proprietario del Server, ma di default è impostato
a 1000 metri. Il Database restituirà solo un valore di visibilità, quello più
alto fra i trovati.
A questo punto il Server provvederà a generare una risposta contenente
tutti i punti della griglia, dove a ognuno di essi è associato un valore di
visibilità che va da 0 a 5:
0. Limpido: Nessuna presenza di nebbie;
1. Caligine: Visibilità superiore ai 10 Km;
23
24
3. Problema Affrontato e Metodologia Utilizzata
2. Foschia: Visibilità compresa fra 1 e 10 Km;
3. Nebbia spessa: Visibilità fino a 200 mt;
4. Nebbia fitta: Visibilità compresa fra 30 e 50 mt;
5. Nebbia densa: Visibilità inferiore a 30 mt.
3.4
Ricerca nel Grafo : Dijskra
In questa fase il Client riceve una griglia di punti, dove a ognuno di essi è
associato un valore di visibilità che sarà utilizzato per calcolare il percorso
ottimale attraverso i Punti di Controllo.
Algoritmo di Dijskra
L’algoritmo di Dijskra è utilizzato per cercare i cammini minimi in un grafo
con o senza ordinamento, ciclico e con pesi non negativi sugli archi [34].
Quest’algoritmo permette in ogni caso, di trovare almeno una soluzione. È
però necessaria un’astrazione per utilizzarlo in un contesto di un cammino
con “nebbia minima”.
Dato un insieme di Punti di Controllo P C, dati due nodi ↵,
2 P C,
dato il peso sull’arco di connessione P (↵, ) e i rispettivi valori di visibilità
V (↵) e V ( ) avremo:
P (↵, ) = max(V (↵), V ( )) [Figura 3.4]
Figura 3.4: Valutazione del parametro di visibilità.
3.4 Ricerca nel Grafo : Dijskra
25
Siamo quasi a buon punto, ma manca ancora un fattore: Il peso per la
distanza. Bisogna quindi riformulare leggermente l’assunzione precedente,
considerando che il peso di un nodo deve essere influenzato dalla distanza.
Dato un insieme di Punti di Controllo P C, dati tre nodi ↵, ,
2 P C,
dati i pesi sugli archi di connessione P (↵, ), P (↵, ), i loro rispettivi valori ambientali V (↵), V ( ), V ( ). Assumendo che la distanza fra ↵ e
che i punti siano dislocati su una griglia, che
e che
= 1,
sia diagonale rispetto a ↵,
sia alla destra di ↵ possiamo quindi calcolare i pesi degli archi di
connessione:
Utilizziamo la formula della diagonale di un quadrato per calcolare la
p
distanza tra il punto ↵ e il punto : D(↵, ) = 1 ⇤ 2 ) 1.4142
quindi:
P (↵, ) = max(V (↵), V ( )) + 1.4142
P (↵, ) = max(V (↵), V ( )) + 1
Figura 3.5: Punti di controllo sulla griglia.
26
3. Problema Affrontato e Metodologia Utilizzata
Innanzitutto ogni Punto di Controllo è inserito come nodo facente parte
del grafo di soluzione, poi per ognuno di questi nodi sono calcolati i pesi degli
archi di connessione ai nodi adiacenti con il metodo appena trovato.
Ora abbiamo tutti i dati necessari per usare l’algoritmo di Dijskra in
modo corretto.
3.5
Correzione della Soluzione
In questa fase è necessaria una correzione dei punti di soluzione trovati
dall’algoritmo di Dijskra. Dato che i Punti di Controllo non sono creati su un grafo stradale preciso, è necessario eliminare il comportamento di
“Allontanamento” che si è verificato in fase di sviluppo (Figura 3.6).
Figura 3.6: Allontanamento parziale dalla meta.
Fin dal primo momento in cui si è verificato l’errore, era chiaro come le
posizioni dei Punti di Controllo fossero il vero problema; ma com’è possibile risolverlo? Bisogna innanzitutto, distinguere le due tipologie di errore
riscontrate: “Allontanamento” e “Inversione”:
Allontanamento : per allontanamento si definisce un comportamento di
variazione di direzione, che non è conforme alla soluzione, né tantomeno
rispetto la direzione di arrivo.
3.5 Correzione della Soluzione
Inversione : per inversione s’intende una variazione di direzione, che viene
interrotta per ritornare sul percorso precedente (inversione a U ).
Una soluzione è composta di un insieme di Punti di Controllo, che collegati tra loro, formano delle rette di direzione. I punti che contengono le rette
di direzione, causano il problema dell’Allontanamento, questo perché nelle
richieste di directions dai server Apple (Cap. 3.2.1), si richiede di passare
per ogni punto che compone la retta (Figura 3.7a). La soluzione sta nell’eliminare tutti i punti che sono “inutili” per la soluzione, lasciando solo il punto
iniziale e finale della retta di direzione (Figura 3.7b).
(a) Direzione con tutti i punti di soluzione della griglia.
(b) Direzione con i punti di soluzione interni alle rette eliminati.
Figura 3.7: Comparazione delle direzioni, prima e dopo la correzione
La direzione calcolata con meno punti di soluzione, è non solo più corretta,
ma anche più veloce per le minor richieste effettuate ai server Apple. Come
27
28
3. Problema Affrontato e Metodologia Utilizzata
si può vedere nell’immagine comparativa (Figura 3.7), dopo aver inserito
l’algoritmo di eliminazione dei punti interni alla retta, il problema è stato
arginato. La soluzione risulta anche più realistica “in termini automobilistici”;
per via del percorso maggiormente ottimizzato in termini di distanza e tempo
di percorrimento.
3.6
Correzione del Percorso
In questa fase le direzioni fra i punti della soluzione, sono state ricevute
dal server Apple, ed è necessario correggere un ulteriore problema sempre
dovuto alla natura dei punti della soluzione: Il problema dell’“Inversione”
(Cap. 3.5). Per risolvere il problema, è necessario capire come funziona il
Sistema di direzione dei server Apple.
Una volta inviate le richieste per ogni coppia di punti soluzione, il Server
Apple risponde asincronamente con oggetti chiamati directions, in questi
oggetti sono contenute, oltre alle informazioni utili per la navigazione, anche
le coordinate dei punti necessari a disegnare la direzione sulla mappa. Dato
che le richieste delle direzioni sono asincrone, è necessario attendere che tutte
le soluzioni siano arrivate, e ricomporre la strada in ordine, partendo dalla
partenza fino all’arrivo.
Ora è possibile notare che nel momento in cui avviene un’Inversione, alcune di queste coordinate sono doppie, bisogna quindi eliminarle dall’insieme
dei punti di direzione pre-calcolati.
Immaginiamo un cammino composto da 6 nodi, e immaginiamo che il
cammino passi per i nodi in quest’ordine: 1-2-3-4-5-4-3-6 (Figura 3.8). Notiamo subito che il cammino sarebbe più corto, se si evitasse di passare per i
nodi 4 e 5. In questo modo otteniamo un insieme di coordinate corrette, che
possono essere usate per disegnare sulla mappa, una strada completamente
priva d’inversioni.
3.7 Struttura del Sistema
Figura 3.8: Esempio di inversione.
3.7
Struttura del Sistema
Il Client è composto dall’applicazione Fog Escaping, che permette ai dispositivi iPhone e iPad, di comunicare con il Server tramite protocollo HTTP.
Il Database contiene tutte le informazioni riguardanti gli utenti e le loro segnalazioni. Il Server riceve le richieste e interrogando il Database, risponde
ai dispositivi.
Figura 3.9: Il Sistema Fog Escaping.
29
Capitolo 4
Implementazione
In questo capitolo saranno introdotti i dettagli dell’implementazione del Sistema. Nella prima sezione sarà introdotta l’architettura di sistema e il protocollo di comunicazione. Nella seconda sezione saranno introdotti i dettagli
d’implementazione del Server HTTP e del Database. Nella terza e ultima
sezione saranno introdotti i dettagli d’implementazione del Client.
4.1
Architettura del Sistema
Il Sistema presenta un’architettura Client-Server; il Client è un applicativo
per dispositivi Apple sia iPhone che iPad, mentre il Server è composto da un
componente web sviluppato in PHP che s’interfaccia a un Database MySQL
per la richiesta e la memorizzazione dei dati.
Il Client può operare sul Server solo se l’Utente completa correttamente
il processo di Registrazione e Login. Una volta autenticato, il Client potrà
utilizzare i servizi per segnalare e richiedere i dati ambientali di Nebbia.
4.1.1
Client
L’applicazione che è stata sviluppata per il progetto di Tesi, si chiama Fog
Escaping. Il nome permette immediatamente d’intuire il compito principale
dell’applicazione; cioè “fuggire dalla nebbia”. Fog Escaping permette a un
31
32
4. Implementazione
Utente di registrarsi, loggarsi, inviare rapidamente una segnalazione di nebbia e calcolare un percorso alternativo da una posizione di partenza a una
di arrivo. Le funzionalità di Fog Escaping, gli permettono in via teorica,
di autosostenersi; infatti, il problema principale delle applicazioni con paradigma Data Crowd-Sourcing, è la massa critica: la presenza di sufficienti
utenti attivi, che permettano al sistema di possedere abbastanza dati capillari da farlo funzionare in modo corretto. Fog Escaping ha alcuni requisiti di
funzionamento legati alla tecnologia utilizzata:
1. Dispositivo iPhone 4 o superiori
2. Dispositivo iPad 3a generazione o superiore
3. Sistema operativo iOS7
L’ambiente di sviluppo utilizzato per la parte Client, è XCode 5, software
proprietario di Apple Inc.
4.1.2
Server
La parte PHP, è composta da alcuni servizi web, che rispondono a determinate richieste, e da un componente che gestisce le connessioni a una base di
dati MySQL.
Il Server è attivo al seguente URL:
http://fogescaping.esy.es/request.php?service=nomeServizio*
Il nomeServizio* può essere uno dei quattro resi disponibili dal Server:
• registration;
• login;
• insertFog: Invio Dato Ambientale di Nebbia;
• checkForFogValues: Richiesta Dati di Nebbia;
4.1 Architettura del Sistema
I requisiti della parte server sono:
1. Server HTTP Apache, versione 2.2.25 o superiore;
2. PHP versione 5.5.3;
3. PDO drivers, in particolare per MySQL 5.5.33 o superiore;
4. MySQL 5.5.33 o superiore
Gli ambienti di sviluppo utilizzati per la parte Server, sono MySQLWorkbench e PHPStorm, rispettivamente per la base di dati e il sorgente PHP.
4.1.3
Protocollo di Comunicazione
Tra il Client e il Server, esiste uno scambio bidirezionale di dati in formato
JSON, attraverso il protocollo di comunicazione HTTP. Si può testare il funzionamento di ogni servizio, utilizzando uno strumento aggiuntivo di Chrome,
chiamato Advanced Rest Client. Le richieste HTTP, sono progettate secondo
l’architettura REST, e per ognuna di esse è indicato:
• il metodo HTTP da utilizzare;
• la struttura dell’URL, i parametri e gli esempi;
• il Body della richiesta;
• l’Header e il Body della risposta.
Risposta Generica di Errore Dati
Il Server provvede a inviare un JSON di risposta generico per Body con dati
mancanti o errati.
1
{
message : " tutti i campi sono richiesti " ,
2
request_time : 1392212902
3
4
}
Listing 4.1: JSON Generico di Errore.
33
34
4. Implementazione
Registrazione
La registrazione richiede all’Utente, l’inserimento di alcuni dati che possano
riconoscerlo univocamente: eMail, Nome, Cognome e Password. Il Server, attuando un controllo sull’e-mail, si assicura che l’Utente non sia già registrato
nel Database, e in seguito provvede a inserirlo.
Client
Server HTTP
Database
Invio JSON (eMail, Nome, Cognome, Password)
Registrazione Utente
JSON di risposta
Controllo
Esistenza
Utente
Risposta
Figura 4.1: Diagramma di Sequenza: Registrazione Utente.
Richiesta:
Metodo: Post
URL: http://fogescaping.esy.es/request.php?service=registration
Body: JSON di Registrazione (Listing 4.2)
Header: Accept: application/json | Content-type:application/json
1
{
2
" email " : " federico . m a c c a f e r r i 2 @ s t u d i o . unibo . it " ,
3
" name " : " Federico " ,
4
" lastname " : " Maccaferri " ,
" password " : " federico "
5
6
}
Listing 4.2: JSON di Registrazione.
I parametri devono tutti essere presenti e non nulli. Nel caso che l’Utente
sia già registrato presso il Database, il Server provvederà a inviare un JSON
4.1 Architettura del Sistema
adeguato (Listing 4.4). Nel caso di errore nei dati, il Server restituirà un
JSON di errore generico (Listing 4.1).
Risposta:
Body: JSON di Registrazione (Listing 4.3-4.4)
Header: Content-type:application/json; charset=utf-8
Il parametro più importante del JSON di risposta è user_id; esso contiene
le informazioni riguardanti l’ID di registrazione presso il Database.
La registrazione non avviene nel caso alcuni parametri non siano corretti,
o quando l’Utente è già registrato. Un ritorno uguale a -1 significa che
l’Utente è già registrato nel Database (Listing 4.4), altrimenti sarà restituito
un JSON di corretta registrazione con l’user_id dell’Utente (Listing 4.3).
1
{
message : " " ,
2
3
request_time : 1392209379 ,
4
user_id : " 2 "
5
}
Listing 4.3: JSON di Registrazione Corretta.
1
{
message : " " ,
2
3
request_time : 1392210112 ,
4
user_id : " -1 "
5
}
Listing 4.4: JSON di Registrazione Errata.
Login
Il Login è il processo che permette all’Utente di autenticarsi, e che permette
al Client di attivare le opzioni di Segnalazione Nebbia e Ricerca Percorso
Alternativo. Sono richiesti due parametri: eMail e Password.
Il Server, dopo la richiesta di Login, restituirà l’ID di registrazione dell’Utente al Database.
35
36
4. Implementazione
Il Client provvederà a salvare l’ID di Login, che verrà utilizzato per le
operazioni di Segnalazione Nebbia e Calcolo Percorso Alternativo.
Client
Server HTTP
Database
Invio JSON (eMail, Password)
Login Utente
JSON di risposta
Controllo
Esistenza
Utente
Risposta
Figura 4.2: Diagramma di Sequenza: Login Utente.
Richiesta:
Metodo: Post
URL: http://fogescaping.esy.es/request.php?service=login
Body: JSON di Login (Listing 4.5)
Header: Accept: application/json | Content-type:application/json
1
{
" email " : " federico . m a c c a f e r r i 2 @ s t u d i o . unibo . it " ,
2
" password " : " federico " ,
3
4
}
Listing 4.5: JSON di Login.
I parametri devono tutti essere presenti e non nulli. Nel caso l’Utente sia
già registrato presso il Database, il Server provvede a inviare un JSON di
risposta adeguato (Listing 4.7). Nel caso di errore nei dati, il Server restituirà
un JSON di errore generico (Listing 4.1).
4.1 Architettura del Sistema
Risposta:
Body: JSON di Risposta (Listing 4.6-4.7)
Header: Content-type:application/json; charset=utf-8
Il parametro più importante del JSON di risposta è user_id; esso contiene le
informazioni riguardanti l’ID di registrazione presso il Database. Se questo
parametro ritorna un valore uguale a -1, l’Utente non è registrato presso il
Database (Listing 4.7), altrimenti è correttamente registrato (Listing 4.6).
1
{
2
message : " " ,
3
request_time : 1392211556 ,
user_id : " 2 "
4
5
}
Listing 4.6: JSON di Login Corretto.
1
{
message : " " ,
2
3
request_time : 1392211913 ,
4
user_id : " -1 "
5
}
Listing 4.7: JSON di Login Errato.
Invio Dato Ambientale di Nebbia
L’Utente tramite l’interfaccia grafica del Client, seleziona la situazione di
visibilità attuale (vedi Cap. 3.3), in seguito il Client richiederà la posizione
dell’Utente e la segnalazione sarà inviata.
37
38
4. Implementazione
Client
Server HTTP
Database
Localizzazione Utente
Invio JSON (Dato Ambientale + Geolocalizzazione)
JSON di risposta
Memorizzazione
Dato Ambientale Geolocalizzato
Risposta
Figura 4.3: Diagramma di Sequenza: Invio Segnalazione.
Richiesta:
Metodo: Post
URL: http://fogescaping.esy.es/request.php?service=insertFog
Body: JSON d’Inserimento Dato Ambientale di Nebbia (Listing 4.8)
Header: Accept: application/json | Content-type:application/json
Com’è possibile vedere nel JSON di Segnalazione della Nebbia, i dati sono
aggregati assieme al dato di posizione dell’Utente, alla condizione di visibilità
(valore da 0 a 5) e all’ID dell’Utente, precedentemente restituito dal processo
di Login.
1
{
2
" userID " : " 1 " ,
3
" lat " : " 44.506484 " ,
4
" lng " : " 11.341968 " ,
" fogValue " : " 5 "
5
6
}
Listing 4.8: JSON Segnalazione Nebbia.
I parametri devono tutti essere presenti e non nulli. Nel caso in cui la Segnalazione vada a buon fine, il Server restituirà un JSON adeguato (Listing 4.9).
4.1 Architettura del Sistema
Nel caso di errore nei dati, il Server restituirà un JSON di errore generico
(Listing 4.1).
Risposta:
Body: JSON di Risposta (Listing 4.9)
Header: Content-type:application/json; charset=utf-8
Il parametro più importante del JSON di risposta è result; esso contiene true se l’inserimento è andato a buon fine, false se l’inserimento non è
stato effettuato; quest’ultimo errore potrebbe avvenire per qualche errore
d’inizializzazione del Server HTTP o del Database.
1
{
message : " " ,
2
3
request_time : 1392215028 ,
4
result : true
5
}
Listing 4.9: JSON Risposta Segnalazione Nebbia.
Richiesta Dati di Nebbia
La richiesta dei dati di Nebbia, è strettamente legata alla funzionalità del
Client di calcolare un percorso alternativo. Il Client invia un insieme di
punti che rappresentano la griglia dei Punti di Controllo (Cap. 3.2) e attende
i valori di visibilità dal Server, dopo che esso ha interrogato per ognuno dei
Punti di Controllo il Database.
39
40
4. Implementazione
Client
Server HTTP
Database
Elaborazione Percorso
Creazione Griglia da
Percorso
Invio JSON (Griglia Punti di Controllo)
Richiesta dato di visibilità
while
esistono punti
Risposta
JSON di risposta
Figura 4.4: Invio Griglia di Punti di Controllo
Richiesta:
Metodo: Post
URL: http://fogescaping.esy.es/request.php?service=checkForFogValues
Body: JSON di Richiesta Dati di Nebbia (Listing 4.10)
Header: Accept: application/json | Content-type:application/json
1
{
" points " :[
2
{
3
4
" lat " :44.838008 ,
5
" lng " :11.152922 ,
" point_id " : " punto1 "
6
7
},
8
{
9
" lat " :44.748008 ,
10
" lng " :11.152922 ,
" point_id " : " punto2 "
11
}
12
]
13
14
}
4.2 Server
41
Listing 4.10: JSON di richiesta dati ambientali.
Risposta:
Body: JSON di Risposta (Listing 4.11)
Header: Content-type:application/json; charset=utf-8
Una volta processati i punti e associato ad ognuno di essi un valore di
visibilità, quello che si ottiene è un JSON così formattato:
1
{
2
" message " : " " ,
3
" request_time " : 1392112251 ,
4
" points " : [
{
5
6
" lat " : 44.838008 ,
7
" lng " : 11.152922 ,
8
" point_id " : " punto1 " ,
" fog_value " : 5
9
10
},
11
{
12
" lat " : 44.748008 ,
13
" lng " : 11.152922 ,
14
" point_id " : " punto2 " ,
" fog_value " : 0
15
}
16
]
17
18
}
Listing 4.11: JSON di risposta dati ambientali.
4.2
Server
Il Processo di implementazione lato Server, è iniziato con la definizione delle
funzionalità che lo stesso doveva implementare. Si è così preferito iniziare
dallo sviluppo del Database MySQL, che rappresenta uno dei punti più importanti del sistema, poiché ad esso sono delegate, la maggior parte delle
42
4. Implementazione
responsabilità. La struttura del Database è molto semplice, poiché rappresenta solo uno strumento di appoggio momentaneo, e in sviluppi futuri dovrà
essere ampliato con funzionalità che permettano la gestione della sicurezza, di controllo sull’affidabilità dei dati ecc.. (Cap. 6.3.5). Il vero cuore
quindi, non è nella struttura ma nelle funzioni che esso ricopre; infatti, sono
implementate alcune stored procedure, che permettono un’analisi veloce dei
dati, direttamente nella sua struttura originaria. Le stored procedure, sono
pensate proprio in visione di un ampliamento della struttura del Database,
poiché rispetto alle query, permettono una modifica della funzionalità lato
Database e non lato Server, in cui è necessario concatenare una moltitudine
di stringhe, per ottenere il medesimo risultato. Inoltre le stored procedure
permettono, a tutti gli effetti, di programmare la base di dati, precompilando
metodi che saranno poi richiamati, da un qualsiasi componente che utilizzi
i Driver MySQL; nel nostro caso PHP con il componente PDO con Driver
MySQL. Il nome della base di dati, per motivi di hosting, è u572804960_fog.
4.2.1
Implementazione Stored Procedure
Le stored procedure rappresentano a tutti gli effetti, i servizi al quale il Server
risponde. Le stored procedure create per il progetto di Tesi sono:
• registration
• login
• insertFogGeoTag
• checkForFogValue
Registrazione
La procedura registration prende in ingresso: la mail dell’Utente, il Nome, il
Cognome e una password.
4.2 Server
1
43
CREATE PROCEDURE registration ( IN mail varchar (255) , IN
firstName varchar (100) , IN secondName varchar (100) , IN
pswd varchar (32) )
Sono dichiarate alcune variabili, che saranno utili al funzionamento della
procedura.
2
BEGIN
3
DECLARE isPresent INT DEFAULT 0;
4
DECLARE aFirstName varchar (20) DEFAULT LOWER ( TRIM ( firstName
));
5
DECLARE aSecondName varchar (20) DEFAULT LOWER ( TRIM (
secondName ) ) ;
6
DECLARE eMail varchar (255) DEFAULT LOWER ( TRIM ( mail ) ) ;
7
DECLARE idUtente INT DEFAULT -1;
Viene fatto un controllo sull’esistenza dell’Utente nella base di dati; se l’Utente esiste, viene inserito il suo ID nella variabile isPresent.
8
SELECT COUNT ( U . idUser ) INTO isPresent
9
FROM User AS U
WHERE U . Mail = eMail ;
10
Se l’Utente è già inserito, la procedura restituirà -1, altrimenti l’ID appena
inserito.
IF isPresent = 0 AND aFirstName != ’ ’ AND aSecondName !=
11
’ ’ AND pswd != ’ ’ AND eMail != ’ ’ THEN
INSERT INTO
12
‘ u572804960_fog ‘. ‘ User ‘ ( ‘ FirstName ‘ ,‘
SecondName ‘ ,‘ Mail ‘ ,‘ Password ‘)
VALUES ( aFirstName ,
13
SET idUtente = LAST_INSERT_ID () ;
14
END IF ;
15
16
17
aSecondName ,
SELECT idUtente ;
END
eMail ,
pswd ) ;
44
4. Implementazione
Login
La procedura login prende in ingresso la mail dell’Utente e la password.
1
CREATE PROCEDURE ‘ u572804960_fog ‘. ‘ login ‘( IN Mail varchar
(255) , IN pswd varchar (32) )
Se viene trovato qualche record corrispondente, nella variabile aIdUser sarà contenuto l’ID dell’Utente trovato. Sarà restituito -1 se l’Utente non è
registrato nella base di dati.
2
BEGIN
3
DECLARE aIdUser INT DEFAULT -1;
4
SELECT U . idUser INTO aIdUser
5
FROM User AS U
6
WHERE U . Mail = Mail AND U . Password = pswd ;
7
IF aIdUser > -1 THEN
SELECT aIdUser AS idUser ;
8
9
10
11
ELSE SELECT aIdUser AS idUser ;
END IF ;
END
Inserimento Dato Ambientale di Nebbia
La procedura insertFogGeoTag prende in ingresso: l’ID dell’Utente, Latitudine, Longitudine e il valore ambientale di Nebbia.
1
CREATE PROCEDURE insertFogGeoTag ( IN idUser INT , IN latitude
FLOAT (12 ,8) , IN longitude FLOAT (12 ,8) , IN fogValue INT )
La procedura restituisce 1 se il record è stato inserito, 0 se qualche dato in
ingresso è nullo.
2
BEGIN
3
IF idUser != ’ ’ AND latitude != ’ ’ AND longitude != ’ ’
4
AND fogValue >= 0 AND fogValue <=5 THEN
5
INSERT INTO FogGeoTag ( ‘ idUser ‘ , ‘ Date ‘ , ‘ Latitude ‘ , ‘
Longitude ‘ , ‘ FogValue ‘)
4.2 Server
6
VALUES ( idUser , NOW () , latitude , longitude , fogValue ) ;
7
SELECT 1 AS inserted ;
8
ELSE SELECT 0 AS inserted ;
9
END IF
10
END
Controllo Dato Ambientale di Nebbia
La procedura checkForFogValue, è sicuramente la più importante, perché permette di trovare segnalazioni di nebbia adiacenti a un Punto di Controllo.
Prende in ingresso Latitudine, Longitudine, un valore di distanza in metri e
un massimo di tempo passato. Gli ultimi due parametri sono importantissimi, poiché permettono di impostare i metri di diametro e di massima validità
di una segnalazione. Questi valori sono impostati in un file di configurazione
PHP, in modo da poter essere modificati con facilità (Cap. 4.2.2).
1
CREATE PROCEDURE checkForFogValue ( IN latitude FLOAT (12 ,8) , IN
longitude FLOAT (12 ,8) , IN maxDistanceInMeters INT , IN
maxElapsedInHours FLOAT )
La procedura utilizza una formula per il calcolo della distanza fra due coordinate geografiche, e restituisce il valore massimo di nebbia riscontrato, assieme
alla distanza in metri della segnalazione scelta.
2
3
BEGIN
SELECT MAX ( C . FogValue ) AS FogValue , C . Latitude , C .
Longitude , C . distance_in_meters AS Distance ,C .
ela psed_t ime_i n_hour s AS ElapsedTime
4
FROM (
5
SELECT
6
F . Latitude , F . Longitude , F . FogValue ,
7
6371 * 2 * ASIN ( SQRT ( POWER ( SIN ( RADIANS ( latitude - ABS ( F .
Latitude ) ) ) , 2)
8
+ COS ( RADIANS ( latitude ) ) * COS ( RADIANS ( ABS ( F . Latitude ) ) )
9
* POWER ( SIN ( RADIANS ( longitude - F . Longitude ) ) , 2) ) )
10
*1000 AS distance_in_meters ,
45
46
11
4. Implementazione
( TIME_TO_SEC ( TIMEDIFF ( NOW () , F . Date ) ) /60) /60 AS
ela psed_t ime_i n_hour s
12
FROM FogGeoTag AS F
13
HAVING distance_in_meters < maxDistanceInMeters AND
ela psed_t ime_i n_hour s < maxElapsedInHours
14
ORDER BY FogValue , distance_in_meters
15
) AS C ;
16
END
4.2.2
Implementazione PHP
L’Implementazione PHP, permette la creazione dei servizi web, accedibili
tramite il protocollo HTTP.
config.php
è il file di configurazione; in esso sono salvate le informazioni che devono
essere presenti, per un corretto funzionamento del Sistema. Fra le variabili
configurabili, sono presenti i dati di accesso alla base di dati, come il nome
dell’host, il nome del Database, il nome Utente e la password.
1
if (! defined ( " db_host " ) ) define ( " db_host " , " mysql . hostinger
. it " ) ;
2
if (! defined ( " db_name " ) ) define ( " db_name " , " u572804960_fog "
3
if (! defined ( " db_username " ) ) define ( " db_username " , "
);
u572804960_fog " ) ;
4
if (! defined ( " db_password " ) ) define ( " db_password " , "
fogescaping " ) ;
Sono inoltre molto importanti questi ultimi valori, poiché rappresentano i
criteri per la validità spaziotemporale delle segnalazioni di Nebbia. Di default, le segnalazioni hanno un diametro di 1000 metri e 6 ore di validità.
4.2 Server
5
if (! defined ( " MA X_D IS TAN CE _IN _M ETE RS " ) ) define ( "
MA X_ DIS TAN CE _IN _M ETE RS " , 1000) ;
6
if (! defined ( " MAX_TIME_IN_HOURS " ) ) define ( "
MAX_TIME_IN_HOURS " , 6) ;
request.php
Questa è la classe che si occupa di gestire le richieste HTTP, attivando i
servizi necessari per l’utilizzo del Sistema. Viene prima instanziato l’oggetto
HttpResponder, che si occuperà di gestire la creazione delle risposte HTTP.
1
require_once ( ’ lib / HttpResponder . php ’) ;
2
$myHR = new HttpResponder () ;
Per ognuno dei servizi, viene controllato che il metodo HTTP utilizzato sia
POST, e che il contenuto del Body abbia tutti i dati necessari. Nel caso
in cui il metodo HTTP utilizzato sia diverso da POST, sarà inviata una
risposta 405 Method Not Allowed ; nel caso in cui il JSON inviato sia errato,
si provvederà a inserire un messaggio “tutti i campi sono richiesti” nel JSON
di risposta.
Per ognuno dei quattro servizi creati, il codice PHP è molto simile; riporto
qui solo il primo servizio implementato: registration.
3
if ( $_GET [ ’ service ’] == ’ registration ’) {
4
$input = file_get_contents ( ’ php :// input ’) ;
5
$data = json_decode ( $input , TRUE ) ;
6
7
if ( $_SERVER [ ’ REQUEST_METHOD ’] != " POST " ) {
$myHR - > methodNotAllowed ( " Metodo " . $_SERVER [ ’
8
REQUEST_METHOD ’ ]. " non supportato da questa risorsa ! " ) ;
9
} else {
if (( $data [ ’ email ’] != " " ) AND ( $data [ ’ name ’] != " " )
10
AND ( $data [ ’ lastname ’] != " " ) AND ( $data [ ’ password ’] != " "
)){
47
48
4. Implementazione
$myHR - > registration ( $data [ ’ email ’] , $data [ ’ name ’] ,
11
$data [ ’ lastname ’] , $data [ ’ password ’ ]) ;
} else {
12
$myHR - > requestDenied ( " tutti i campi sono
13
richiesti " ) ;
}
14
}
15
16
}
HttpResponder.php
La classe HttpResponder, si occupa di gestire la creazione delle risposte
HTTP. Essa importa la classe Controller.php, che si occupa di fare da “centro
di smistamento” per le richieste al Database. I metodi implementati sono:
requestDenied(), methodNotAllowed(), registration(), login(), insertFogGeoTag(), checkForFogValue(). HttpResponder implementa anche un semplice
metodo chiamato setHeadersFor200OK(); esso crea un Header adatto alla
risposta HTTP 200, che verrà utilizzato nella maggior parte dei casi.
1
public static function setHeadersFor200OK () {
header ( ’ Content - type : application / json ; charset = utf -8
2
’) ;
if ( $_SERVER [ ’ SERVER_PROTOCOL ’] != " HTTP /1.1 " ) {
3
4
header ( ’ Connection : close ’) ;
5
header ( " HTTP /1.0 200 OK " ) ;
} else {
6
header ( " HTTP /1.1 200 OK " ) ;
7
}
8
9
}
Il metodo requestDenied ha il compito di notificare al Client, che una richiesta
effettuata, non può essere presa in carico per mancanza di dati o per errori
negli stessi. Esso prende in ingresso una stringa, che sarà poi aggiunta nel
campo messaggio del JSON di risposta (esempio nel Listing 4.1).
4.2 Server
10
49
public static function requestDenied ( $cause ) {
11
d a t e _ d ef a u l t _ t i m e z on e _ s e t ( " UTC " ) ;
12
self :: setHeadersFor200OK () ;
13
$response = array (
14
" message " = > $cause ,
15
" request_time " = > time ()
16
);
17
$json = json_encode ( $response ) ;
18
echo $json ;
19
}
Il metodo methodNotAllowed, ha il compito di notificare al Client che il metodo HTTP utilizzato per la richiesta, non è permesso. Tutti i servizi attivi
sul Server HTTP, rispondono solo al metodo POST, quindi ogni altro metodo come GET o DELETE, ritorneranno una risposta di codice 405. Com’è
possibile notare, tra riga 24 e 28, il metodo è compatibile sia con il protocollo
HTTP 1.1, che HTTP 1.0.
20
public static function methodNotAllowed ( $cause ) {
d a t e _ d ef a u l t _ t i m e z on e _ s e t ( " UTC " ) ;
21
22
header ( ’ Content - type : application / json ; charset = utf -8
23
’) ;
24
if ( $_SERVER [ ’ SERVER_PROTOCOL ’ ]!= " HTTP /1.1 " ) {
25
header ( ’ Connection : close ’) ;
26
header ( " HTTP /1.0 405 Method Not Allowed " ) ;
27
} else {
header ( " HTTP /1.1 405 Method Not Allowed " ) ;
28
29
}
30
31
$response = array (
32
" message " = > $cause ,
33
" request_time " = > time ()
34
);
35
$json = json_encode ( $response ) ;
36
echo $json ;
50
37
4. Implementazione
}
Il metodo registration, ha il compito di notificare al Client, il responso riguardante la registrazione. Il metodo, come i successivi che elencherò, richiamano
la classe Controller.php, per richiedere la registrazione dell’Utente con i dati
a disposizione. Prende in ingresso email, nome, cognome e password dell’Utente, e restituisce l’ID dell’Utente appena inserito nel Database. L’ID di
risposta, sarà invece uguale a -1 quando l’Utente è già registrato presso il
Database.
38
public function registration ( $email , $name , $lastname ,
$password ) {
39
d a t e _ de f a u l t _ t i m e zo n e _ s e t ( " UTC " ) ;
40
$userID = Controller :: registration ( $email , $name ,
$lastname , $password ) ;
41
$response = array (
42
43
" message " = > " " ,
44
" request_time " = > time () ,
45
" user_id " = > $userID
);
46
47
48
$json = json_encode ( $response ) ;
49
self :: setHeadersFor200OK () ;
50
echo $json ;
51
}
Il metodo login ha il compito di notificare al Client, il responso riguardante il
“Login” dell’Utente; in realtà, considerata la natura del Sistema, non è un vero
e proprio Login, poiché non viene memorizzata nessuna sessione riguardante il
Client. Il metodo prende in ingresso email e password dell’Utente e restituisce
l’ID di registrazione presso il Database, che sarà poi memorizzato all’interno
del Client e utilizzato nelle richieste di insertFogGeoTag e checkForFogValues.
4.2 Server
51
52
public function login ( $email , $password ) {
53
d a t e _ d ef a u l t _ t i m e z on e _ s e t ( " UTC " ) ;
54
$userID = Controller :: login ( $email , $password ) ;
55
$response = array (
56
57
" message " = > " " ,
58
" request_time " = > time () ,
59
" user_id " = > $userID
);
60
61
62
$json = json_encode ( $response ) ;
63
self :: setHeadersFor200OK () ;
64
echo $json ;
65
}
Il metodo insertFogGeoTag, ha il compito di notificare al Client, il responso riguardante l’inserimento di un dato ambientale di Nebbia. Prende in
ingresso l’ID dell’Utente restituito dal processo di Login, Latitudine, Longitudine e il valore di Nebbia dichiarato dalla segnalazione. Restituisce true,
se l’operazione è andata a buon fine, false altrimenti.
66
public function insertFogGeoTag ( $userID , $lat , $lng ,
$fogValue ) {
67
d a t e _ d ef a u l t _ t i m e z on e _ s e t ( " UTC " ) ;
68
$inserted = Controller :: insertFogGeoTag ( $userID , $lat ,
$lng , $fogValue ) ;
69
70
( $inserted == 1) ? $result = true : $result = false ;
71
72
$response = array (
73
" message " = > " " ,
74
" request_time " = > time () ,
75
" result " = > $result
76
);
77
78
$json = json_encode ( $response ) ;
79
self :: setHeadersFor200OK () ;
52
4. Implementazione
echo $json ;
80
81
}
Il metodo checkForFogValue, ha il compito di generare una risposta, dove
per ogni Punto di Controllo appartenente alla griglia, viene associato un
valore di visibilità richiesto al Database. Ogni Punto di Controllo deve quindi
mantenere le sue proprietà principali, di latitudine, longitudine e id; questo
per la corretta ricostruzione della griglia lato Client.
82
public function checkForFogValue ( $points ) {
d a t e _ de f a u l t _ t i m e zo n e _ s e t ( ’ UTC ’) ;
83
84
85
$fogPoints = array () ;
86
foreach ( $points as $point ) {
$pointData = Controller :: checkForFogValue ( $point [
87
’ lat ’] , $point [ ’ lng ’ ]) ;
$newPoint = array (
88
89
" lat " = > $point [ ’ lat ’] ,
90
" lng " = > $point [ ’ lng ’] ,
91
" point_id " = > $point [ ’ point_id ’] ,
92
" fog_value " = > ( int ) $pointData [0][ ’ FogValue ’]
);
93
94
array_push ( $fogPoints , $newPoint ) ;
95
}
96
97
$response = array (
98
" message " = > " " ,
99
100
" request_time " = > time () ,
101
" points " = > $fogPoints
);
102
103
$json = json_encode ( $response ) ;
104
self :: setHeadersFor200OK () ;
105
echo $json ;
106
}
4.2 Server
Controller.php
La classe Controller.php, si occupa di smistare ogni richiesta diretta al Database. Tutti i metodi utilizzano la classe DBHandler.php, che si occupa
di generare le richieste al Database per le stored procedure. I metodi implementati sono: registration(), login(), insertFogGeoTag(), checkForFogValue(). Ognuno di questi metodi richiama la funzione relativa dall’oggetto
singleton DBHandler.
Metodo di Registrazione
1
public static function registration ( $email , $name ,
$lastname , $password )
2
{
3
$dbHandler = DBHandler :: singleton () ;
4
$result = $dbHandler - > callProcedure ( array ( $email ,
$name , $lastname , $password ) ," registration " ) ;
5
return $result [0][ ’ idUtente ’ ];
6
7
}
Metodo di Login.
8
9
public static function login ( $email , $password )
{
10
$dbh = DBHandler :: singleton () ;
11
$result = $dbh - > callProcedure ( array ( $email , $password
) ," login " ) ;
12
return $result [0][ ’ idUser ’ ];
13
14
}
Metodo d’Inserimento dato ambientale di Nebbia.
15
public static function insertFogGeoTag ( $userID , $lat ,
$lng , $fogValue )
16
{
53
54
4. Implementazione
17
$dbh = DBHandler :: singleton () ;
18
$result = $dbh - > callProcedure ( array ( $userID , $lat ,
$lng , $fogValue ) ," insertFogGeoTag " ) ;
19
return $result [0][ ’ inserted ’ ];
20
21
}
Metodo di richiesta dato ambientale di Nebbia. Esso utilizza i valori
MAX_DISTANCE_IN_METERS e MAX_TIME_IN_HOURS, entrambi
provenienti da Config.php.
22
public static function checkForFogValue ( $lat , $lng ) {
23
$dbh = DBHandler :: singleton () ;
24
$result = $dbh - > callProcedure ( array ( $lat , $lng ,
MAX_DISTANCE_IN_METERS , MAX_TIME_IN_HOURS ) ,"
checkForFogValue " ) ;
25
return $result ;
26
27
}
DBHandler.php
La classe DBHandler.php rappresenta la vera e propria connessione con il
Database. La classe è implementata con il pattern Singleton, in modo che
per ogni Utente, ci sia una sola istanza di questo oggetto.
1
class DBHandler {
2
private static $instance ;
3
private function __construct () {}
4
public static function singleton ()
5
{
6
if (! isset ( self :: $instance ) ) {
7
// instantiating class if istance doesn ’t exists
8
// $className = __CLASS__ ;
9
self :: $instance = new DBHandler () ;
10
}
11
// returning class instance
4.2 Server
55
return self :: $instance ;
12
13
}
14
private function __clone () {}
Il metodo callProcedure, prende in ingresso una array di valori e il nome
della procedura che dovrà essere richiamata. Qualora al posto dell’array sia
passata una stringa, essa sarà interpretata come un array di un solo elemento.
15
public function callProcedure ( $values , $procedureName ) {
if ( sizeof ( $values ) >0 and ( is_array ( $values ) or
16
is_string ( $values ) ) ) {
try {
17
Viene poi richiamato l’oggetto PDO, nel quale sono inseriti i dati provenienti
da Config.php essenziali per la connessione dal Database.
18
// initializing PDO and establishing DB connection
$db = new PDO ( " mysql : host = " . db_host . " ;
19
dbname = " . db_name . " ; charset = utf8 " , db_username , db_password ,
array (
PDO :: MY SQ L _A TT R_ I NI T_ C OM MA ND = > " SET
20
NAMES utf8 " ) ) ;
$query = " CALL " . db_name . " . " . $procedureName . "
21
(";
In seguito, i valori contenuti nell’array, sono concatenati per comporre la
richiesta per una determinata stored procedure.
22
23
if ( is_array ( $values ) ) {
// if i = 0 = > first iteration
24
$i = 0;
25
foreach ( $values as $value ) {
26
if ( $i == 0) {
27
$query = $query . " ? " ;
28
} else {
29
$query = $query . " ,? " ;
56
4. Implementazione
30
}
31
$i ++;
32
}
33
$query = $query . " ) ; " ;
34
}
A questo punto è necessario preparare il Database per l’accoglimento della
stored procedure.
35
$stmt = $db - > prepare ( $query ) ;
36
if ( is_array ( $values ) ) {
37
// using the " j " index to bind the parameter
38
$j = 0;
39
foreach ( $values as $value ) {
// DO NOT USE $value instead of $values [ $j ]. PDO doesn ’t
40
work this way even if $value should be correct
$stmt - > bindParam ( $j +1 , $values [ $j ] , PDO :: PARAM_STR ) ;
41
$j ++;
42
}
43
44
}
Viene eseguita la stored procedure, e viene salvato il contenuto della risposta
all’interno della variabile $result.
45
// executing procedure
46
$rs = $stmt - > execute () ;
47
if (! $rs ) { $error_code = $stmt - > errorCode () ;
if ( $error_code == ’ 42000 ’) {
48
// return " < p class =\" error \" > query
49
syntax error : " . $error_code . " </p >";
return ( " Query syntax error , error
50
code : 42000:\ n " ) ; exit () ;
}
51
52
}
53
$result = $stmt - > fetchAll ( PDO :: FETCH_ASSOC ) ;
Infine viene interrotta la connessione al Database, e viene restituita la variabile $result.
4.3 Client
57
54
$db = null ;
55
return $result ;
56
} catch ( PDOException $ex ) {
// die ( ’ db error ’) ;
57
echo ( " ERROR :\ n " . $ex - > getMessage () ) ; exit () ;
58
}
59
60
}}
4.3
Client
L’implementazione della parte Client, è un applicazione pensata per funzionare sulle piattaforme mobili Apple, sia iPhone che iPad. Si è preferito
sviluppare direttamente sui dispositivi invece che su un simulatore, questo
per garantire la qualità del prodotto.
La piattaforma XCode di Apple, permette di sviluppare sia la parte
grafica che il codice, inoltre gli strumenti messi a disposizione, aiutano lo
sviluppatore a trovare facilmente gli errori, inevitabili durante la scrittura.
L’applicazione Fog Escaping è sviluppata secondo il pattern MVC (ModelView-Controller), che aiuta a tenere separati i componenti grafici dalla logica,
inoltre che a garantire l’alta riusabilità dei componenti.
Figura 4.5: Pattern Model-View-Controller.
L’implementazione è iniziata con lo studio dei sistemi di direzionamento
di Apple; l’obiettivo era capire quale livello di precisione si sarebbe potuto
raggiungere. Purtroppo non è possibile accedere ai dati sui nodi stradali,
quindi era necessario trovare un metodo alternativo (Cap. 3.2).
58
4. Implementazione
Fog Escaping ha due interfacce grafiche distinte, una per iPhone e una
per iPad; sono quindi differenti i metodi con il quale si devono gestire gli
spostamenti tra una View e un’altra. Per iPhone si è preferito utilizzare una
navigazione modale, che permette di far comparire le opzioni dal basso, mantenendo quindi una gerarchia dove dalla View principale, ci si può spostare
verso ognuna delle altre (Figura 4.6).
Figura 4.6: Storyboard iPhone.
Per iPad la metodologia è decisamente diversa, poiché per le opzioni basilari, come la segnalazione del dato ambientale di Nebbia e la ricerca di un
percorso alternativo, si è preferito utilizzare i Popover; essi permettono la
visualizzazione del contenuto, senza mai uscire dalla View principale (Figura
4.7).
4.3 Client
59
Figura 4.7: Storyboard iPad.
4.3.1
Notification
Data la natura asincrona delle richieste, è stato necessario gestire alcuni passaggi, tramite le Notification di Apple. Esse permettono di notificare a uno o
più Observer, il cambiamento di uno stato; nell’applicazione sono inserite per
gestire i JSON di ritorno dal Server e per effettuare operazioni. Ad esempio
quando il Client ha inserito i dati di Login, prima di variare uno stato grafico, è necessario attendere il JSON di risposta del Server e successivamente
decidere se permettere il Login, oppure far notificare all’Utente che i dati non
sono corretti.
4.3.2
RoutePlanningViewController
La classe RoutePlanningViewController ha lo scopo di gestire l’interfaccia
grafica principale del sistema. Essa comprende: la mappa in primo piano,
60
4. Implementazione
in alto i pulsanti di Login/Logout e ricerca percorso alternativo, in basso il
pulsante di segnalazione dello stato ambientale di Nebbia.
Interfaccia
L’interfaccia definisce alcune Property, necessarie alla gestione dei componenti grafici e una variabile ZOOM_QUARTIER che servirà per il corretto
zoom iniziale della mappa.
1
# import < UIKit / UIKit .h >
2
# import < MapKit / MapKit .h >
3
4
# define ZOOM_QUARTIER 10000
5
6
@interface R o u t e P l a n n i n g V i e w C o n t r o l l e r : U I V i e w C o n t r o l l e r
7
@property ( strong , nonatomic ) IBOutlet MKMapView * mapView ;
8
@property ( nonatomic , strong ) C L L o c a t i o n M a n a g e r * lo ca t io nM a na g er ;
9
@property ( strong , nonatomic ) IBOutlet U IB a rB ut t on It e m * l o g i n L o g o u t B u t t o n ;
10
@property ( strong , nonatomic ) IBOutlet U IB a rB ut t on It e m * f o gG e oT ag B ut to n ;
11
@property ( strong , nonatomic ) IBOutlet U IB a rB ut t on It e m * escapeButton ;
12
@property ( strong , nonatomic ) IBOutlet U I A c t i v i t y I n d i c a t o r V i e w *
13
@property ( strong , nonatomic ) IBOutlet UILabel * i n f o L o a d i n g L a b e l ;
14
@end
mapActivityIndicator ;
viewDidLoad:
Quando la View sta per essere caricata, il sistema richiama il metodo viewDidLoad, nel quale sono fatte le inizializzazioni delle variabili d’istanza.
In seguito è inizializzato il CLLocationManager ; esso si occupa di richiedere
la posizione dell’Utente al dispositivo.
1
- ( void ) viewDidLoad
2
{
3
4
[ super viewDidLoad ];
if (! _ l o c a t i o n M a n a g e r ) _ l o c a t i o n M a n a g e r = [[ C L L o c a t i o n M a n a g e r alloc ] init
];
5
_ l o c a t i o n M a n a g e r . delegate = self ;
6
_ l o c a t i o n M a n a g e r . de s ir e dA cc u ra cy = k C L L o c a t i o n A c c u r a c y K i l o m e t e r ;
7
[ self s h o w U s e r L o c a t i o n ];
8
r e a d y T o R e m o v e I n v e r s i o n = NO ;
9
_ i n f o L o a d i n g L a b e l . text = @ " " ;
4.3 Client
10
_mapView . delegate = self ;
11
logout = [ self is Al r ea dy L og ge d ];
12
if ( logout ) {
_ l o g i n L o g o u t B u t t o n . title = @ " Logout " ;
13
}
14
[ self i n i t C o m p o n e n t G r a p h i c s M o d i f i c a t i o n ];
15
16
}
In questa fase la classe RoutePlanningViewController, si mette in ascolto su
alcune Notification, che permetteranno di riflettere coerentemente lo stato
della richiesta effettuata, con lo stato grafico necessario.
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
17
@selector ( sendFogValue :) name : @ " fogValue " object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
18
@selector ( escapeFromFog :) name : @ " escape " object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
19
@selector ( r e c e i v e S o l u t i o n F r o m G r i d :) name : @ " solution - ready " object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
20
@selector ( r e c e i v e G r i d W i t h F o g :) name : @ " grid - ready " object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
21
@selector ( c o nn e ct io n Er ro r :) name : @ " connection - error " object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
22
@selector ( routeReady :) name : @ " route - ready " object : nil ];
sendFogValue:
Il metodo sendFogValue viene richiamato al ricevimento della Notification
relativa all’inserimento del dato ambientale di Nebbia. Utilizza la classe
FogRequest (Cap. 4.3.10) per la gestione della richiesta HTTP, riguardante
il servizio insertFogValue (Cap. 4.1.3).
23
- ( void ) sendFogValue :( NS Notifi cation *) notification {
NSNumber * fogValue = [ notification object ];
24
25
FogRequest * req = [[ FogRequest alloc ] init ];
26
[ req i n s e r t F o g D a t a W i t h C o o r d i n a t e : _ l o c a t i o n M a n a g e r . location . coordinate
andFogValue :[ fogValue intValue ]];
[ _ f o g G e o T a g P o p o v e r d i s m i s s P o p o v e r A n i m a t e d : YES ];
27
28
}
61
62
4. Implementazione
escapeFromFog:
Il metodo escapeFromFog, viene richiamato al ricevimento della Notification,
relativa al calcolo di un percorso alternativo. Come specificato nelle sezioni
precedenti, prima di generare la richiesta HTTP per i dati di nebbia, è necessario richiedere il percorso ottimale (Cap. 3.2.1), e la Griglia dei Punti di
Controllo (Cap. 3.2.2). Viene quindi richiamato il metodo di classe loadStandardRouteWithStartLocation:andArriveLocation, che si occupa di generare la
sequenza degli eventi che porteranno alla presentazione della richiesta HTTP.
checkForFogValues.
29
- ( void ) escapeFromFog :( N SNotif icatio n *) notification {
30
_ i n f o L o a d i n g L a b e l . text = @ " Processamento Dati " ;
31
[ _ i n f o L o a d i n g L a b e l setHidden : NO ];
32
[ self i n i t C o m p o n e n t A n d V a r i a b i l e s ];
33
[ self r e s e t A l l M a p C o n t e n t s ];
34
[ self s ta rt M ap L oa di n g ];
35
NSArray * locations = [ notification object ];
36
CLLocation * start = locations [0];
37
CLLocation * arrive = locations [1];
38
[ self l o a d S t a n d a r d R o u t e W i t h S t a r t L o c a t i o n : start a n d A r r i v e L o c a t i o n : arrive
];
39
}
loadStandardRouteWithLocation:andArriveLocation:
Il metodo loadStandardRouteWithLocation:andArriveLocation, richiamerà il
metodo findDirectionsFrom:to, che ha il compito di richiedere ai Server Apple
il percorso ottimale tra un punto di partenza e un punto di arrivo. Il percorso
calcolato sarà poi passato al metodo, useDirections:.
40
M K D i r e c t i o n s R e q u e s t * request = [[ M K D i r e c t i o n s R e q u e s t alloc ] init ];
41
[ request setSource : source ];
42
[ request se tDesti nation : destination ];
43
request . r e q u e s t s A l t e r n a t e R o u t e s = NO ;
44
45
MKDirections * directions = [[ MKDirections alloc ] i ni t Wi th R eq u es t : request
];
46
47
// make network indicator visible
[[ UIApplication s h a r e d A p p l i c a t i o n ] s e t N e t w o r k A c t i v i t y I n d i c a t o r V i s i b l e :
YES ];
4.3 Client
63
48
__weak R o u t e P l a n n i n g V i e w C o n t r o l l e r * weakSelf = self ;
49
[ directions c a l c u l a t e D i r e c t i o n s W i t h C o m p l e t i o n H a n d l e r :
50
^( M K D i r e c t i o n s R e s p o n s e * response , NSError * error ) {
if ( error ) {
51
NSLog ( @ " Error is % @ " , error ) ;
52
NSString * errorString = @ " Richiesta di Direzione non
53
disponibile al momento " ;
if ( error . code == 5) {
54
errorString = @ " Direzione non disponibile al momento . " ;
55
}
56
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle : @ " Fog
57
Escaping " message : errorString delegate : nil c a n c e l B u t t o n T i t l e : @ " OK "
o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
58
59
// activate the program for other actions
60
[ self stopMa pLoadi ng ];
} else {
61
62
_ i n f o L o a d i n g L a b e l . text = @ " Processamento Dati di Direzione " ;
63
[ weakSelf useDirections : response ];
}
64
}];
65
66
}
useDirections:
Il metodo useDirections, si occupa principalmente di salvare il percorso ottimale generato dai servizi Apple, e infine di creare l’oggetto Grid che rappresenta la griglia dei Punti di Controllo . Sarà direttamente l’oggetto Grid
ad occuparsi della richiesta HTTP, e invierà una Notification quando tutti i
dati di visibilità, saranno ritornati dal Server.
67
- ( void ) useDirections :( M K D i r e c t i o n s R e s p o n s e *) response
68
{
69
// Lazy instantiation for routes array of points
70
if (! _routes ) {
_routes = [[ N SMutab leArra y alloc ] i n i t W i t h C a p a c i t y :[ response . routes count
71
]];
72
} else {
[ _routes r e m o v e A l l O b j e c t s ]; // remove all the precedent routes from the
73
array
74
}
75
76
MKRoute * route = response . routes [0];
77
// estract the polyline from route
64
4. Implementazione
78
MKPolyline * line = route . polyline ;
79
// extract all the points from the polyline
80
NSMu tableA rray * array = [[ NSMut ableAr ray alloc ] i n i t W i t h C a p a c i t y :[ line
81
for ( int i = 0; i < line . pointCount ; i ++) {
pointCount ]];
82
C L L o c a t i o n C o o r d i n a t e 2 D coord = M K C o o r d i n a t e F o r M a p P o i n t ( line . points [ i ]) ;
83
CLLocation * location = [[ CLLocation alloc ] i n i t W i t h L a t i t u d e : coord .
latitude longitude : coord . longitude ];
// print test for route points
84
85
RoutePoint * point = [[ RoutePoint alloc ] init ];
86
point . location = location ;
[ array addObject : point ];
87
88
}
89
[ _routes addObject : array ];
90
91
// insert intermediate point to A - B segment too long
92
[ self c o r r e c t R o u t e s F o r L o n g S t r a i g h t D i s t a n c e ];
93
_ i n f o L o a d i n g L a b e l . text = @ " Richiesta Dati Ambientali " ;
94
_grid = [[ Grid alloc ] i n i t G r i d W i t h R o u t e : _routes [0]];
95
}
receiveGridWithFog:
Quando la Griglia è stata completamente costruita, viene richiamato il metodo receiveGridWithFog, che si occupa di cambiare la label delle info di
caricamento e di inviare la Griglia al metodo che troverà il “cammino di
nebbia minima”.
96
- ( void ) r e c e i v e G r i d W i t h F o g :( NSNot ificat ion *) notification {
dis patch_ async ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
97
[[ UIApplication s h a r e d A p p l i c a t i o n ]
98
s e t N e t w o r k A c t i v i t y I n d i c a t o r V i s i b l e : NO ];
_ i n f o L o a d i n g L a b e l . text = @ " Processamento Dati Ambientali " ;
99
100
}) ;
101
[ _grid gridReady :[ notification object ]];
102
}
receiveSolutionFromGrid:
Quando la soluzione sarà stata calcolata, essa dovrà ripassare per il RoutePlanningViewController per essere corretta e poi visualizzata sulla mappa.
4.3 Client
65
Un passaggio molto importante, è la correzione della soluzione tramite il
metodo correctSolution, che si occupa di eliminare i punti interni alla retta
come specificato nel Capitolo 3.5. Successivamente sono numerati i punti di
soluzione, in modo che possano essere calcolati correttamente i percorsi fra
un punto e l’altro.
103
- ( void ) r e c e i v e S o l u t i o n F r o m G r i d :( NSN otific ation *) notification {
104
NSArray * s ol ut i on An d Gr id = [ notification object ];
105
NSArray * solution = [ self c o rr e ct So l ut io n : so l ut io n An d Gr id [0]];
106
_ so lu t io nP o in ts = solution ;
107
NSArray * gridPoints = s ol ut i on A nd Gr i d [1];
108
// numering the route points
109
for ( int i = 0; i <[ _routes [0] count ]; i ++) {
110
RoutePoint * p = _routes [0][ i ];
111
p . number = [ NSNumber numberWithInt : i ];
112
}
Sono caricate sulla mappa, le informazioni riguardanti lo stato delle Nebbie,
in modo da avere un paragone visivo.
113
_ r o u t e S o l u t i o n F o r A l t e r n a t i v e = [ solution copy ];
114
for ( int i = 0; i <[ gridPoints count ] ; i ++) {
115
ControlPoint * point = gridPoints [ i ];
116
CLLocation * loc = point . location ;
117
if ([ point . levelOfFog intValue ] >=1) {
fog ValueT oShow = [ point . levelOfFog intValue ];
118
M K P o i n t A n n o t a t i o n * annotation =[ self
119
c r e a t e M a p A n n o t a t i o n F o r C o o r d i n a t e : loc . coordinate andTitle : text
andFogValue :[ NSNumber numberWithInt : fogV alueTo Show ]];
[ _mapView addAnnotation : annotation ];
120
}
121
122
}
Infine sono visualizzate sulla Mappa, le direzioni fra un Punto di Controllo
e un altro, in modo da creare un percorso alternativo completo.
123
a ll Ro u te To C ou nt = [ solution count ];
124
if (! _ a l t e r n a t i v e R o u t e ) _ a l t e r n a t i v e R o u t e = [[ NSMu tableA rray alloc ] init ];
125
[ _ a l t e r n a t i v e R o u t e r e m o v e A l l O b j e c t s ];
126
127
for ( int i = 0; i <[ solution count ]; i ++) {
128
ControlPoint * p1 = solution [ i ];
129
if ([ solution count ] > i +1) {
66
4. Implementazione
130
ControlPoint * p2 = solution [ i +1];
131
// itering until destination point
132
[ self f i n d D i r e c t i o n s F r o m S t a r t P o i n t : p1 . location . coordinate
andArrive : p2 . location . coordinate from : i to : i +1];
}
133
}
134
135
}
4.3.3
LoginViewController
LoginViewController, è la classe imputata alla gestione grafica di Login dell’Utente. Nell’interfaccia grafica, è presente il pulsante Registrazione; se
premuto, aziona un modal segue, che caricherà la View di Registrazione
(Cap. 4.3.4). L’interfaccia contiene le Property necessarie alla gestione dei
componenti grafici.
136
# import < UIKit / UIKit .h >
137
138
@interface L o g i n V i e w C o n t r o l l e r : U I V i e w C o n t r o l l e r
139
@property ( strong , nonatomic ) IBOutlet UITextField * ema ilText Field ;
140
@property ( strong , nonatomic ) IBOutlet UITextField * p a s s w o r d T e x t F i e l d ;
141
@property ( strong , nonatomic ) IBOutlet U I A c t i v i t y I n d i c a t o r V i e w *
142
@property ( strong , nonatomic ) IBOutlet UILabel * infoLogin ;
143
@end
activityIndicator ;
viewDidLoad
In questa fase si inizializzano i componenti grafici e si imposta la classe come
Observer sulle Notification di Login: loginAccepted e loginFailed.
1
- ( void ) viewDidLoad
2
{
3
[ super viewDidLoad ];
4
_ em ai l Te xt F ie l d . delegate = self ;
5
_ p a s s w o r d T e x t F i e l d . delegate = self ;
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
6
@selector ( loginSuccess :) name : loginAccepted object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
7
@selector ( loginError :) name : loginFailed object : nil ];
8
}
4.3 Client
requestAccess:
Sicuramente è uno dei metodi più importanti della classe; esso si occupa di
controllare i dati inseriti dall’Utente, richiamare il metodo di Login, oppure
notificare eventuali errori d’inserimento.
9
- ( IBAction ) requestAccess :( id ) sender {
[ _ a c t i v i t y I n d i c a t o r sta rtAnim ating ];
10
if (![ _ em ai l Te x tF ie l d . text i s Eq ua l To St r in g : @ " " ] && ![ _ p a s s w o r d T e x t F i e l d .
11
text i sE qu a lT oS t ri ng : @ " " ]) {
12
NSString * email = _e m ai l Te xt F ie ld . text ;
13
NSString * password = _ p a s s w o r d T e x t F i e l d . text ;
14
FogRequest * req = [[ FogRequest alloc ] init ];
15
[ req l oginWi thEmai l : email andPassword : password ];
[ self hideKeyboard ];
16
} else {
17
NSLog ( @ " Errore login : Dati mancanti " ) ;
18
19
_infoLogin . text = @ " Username o Password Mancanti " ;
20
[ _ a c t i v i t y I n d i c a t o r stopAnimating ];
}
21
22
}
cancel:
Il metodo cancel: ha il semplice compito di chiudere la View e ritornare alla
precedente. Questo metodo è necessario solo per la versione iPhone.
23
- ( IBAction ) cancel :( id ) sender {
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
24
25
}
loginSuccess:
Quando il Login viene effettuato con successo, viene richiamato il seguente metodo dall’Observer. Esso si occupa di gestire i componenti grafici richiamandoli direttamente dal Thread principale; in questo modo è possibile modificarli all’istante. Successivamente si ritorna alla View precedente,
notificando l’Utente con un Alert adeguato (Figura 6.15a).
67
68
26
4. Implementazione
- ( void ) loginSuccess :( NS Notifi cation *) notification {
27
// essential for istant message on main queue
28
dis patch_ async ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
29
_infoLogin . text = @ " Login Effettuato . " ;
30
[ _ a c t i v i t y I n d i c a t o r stopAnimating ];
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle : @ " Fog
31
Escaping " message : @ " Login Effettuato . " delegate : nil c a n c e l B u t t o n T i t l e : @ "
OK " o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
32
}) ;
33
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
34
35
}
loginError:
Quando il Server risponde con un JSON di Login Errato, è necessario notificare all’utente che i dati inseriti non sono corretti. Viene quindi inserito
un messaggio di testo direttamente nella View, in questo modo l’Utente può
decidere di inserire nuovi dati di Login (Figura 6.15a).
36
- ( void ) loginError :( NSNot ificat ion *) notification {
37
// essential for istant message on main queue
38
dis patch_ async ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
39
_infoLogin . text = @ " Username o Password Errati " ;
40
[ _ a c t i v i t y I n d i c a t o r stopAnimating ];
}) ;
41
42
}
4.3.4
RegistrationViewController
La classe RegistrationViewController, si occupa di gestire la Registrazione
dell’Utente. L’interfaccia dichiara i componenti grafici e le relative Property
1
# import < UIKit / UIKit .h >
2
3
@interface R e g i s t r a t i o n V i e w C o n t r o l l e r : U I V i e w C o n t r o l l e r
4
@property ( strong , nonatomic ) IBOutlet UITextField * name ;
5
@property ( strong , nonatomic ) IBOutlet UITextField * lastName ;
6
@property ( strong , nonatomic ) IBOutlet UITextField * mail ;
4.3 Client
7
@property ( strong , nonatomic ) IBOutlet UITextField * password1 ;
8
@property ( strong , nonatomic ) IBOutlet UITextField * password2 ;
9
@property ( strong , nonatomic ) IBOutlet U I A c t i v i t y I n d i c a t o r V i e w * activity ;
10
@property ( strong , nonatomic ) IBOutlet UILabel * r e g i s t r a t i o n I n f o ;
11
12
@end
viewDidLoad:
Il metodo inizializza i componenti grafici e aggiunge la classe come Observer
sulle seguenti Notification: registrationAccepted e registrationFailed.
1
- ( void ) viewDidLoad
2
{
3
[ super viewDidLoad ];
4
_mail . delegate = self ;
5
_name . delegate = self ;
6
_lastName . delegate = self ;
7
_password1 . delegate = self ;
8
_password2 . delegate = self ;
9
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
@selector ( r e g i s t r a t i o n S u c c e s s :) name : r e g i s t r a t i o n A c c e p t e d object : nil ];
[[ N S N o t i f i c a t i o n C e n t e r defaultCenter ] addObserver : self selector :
10
@selector ( r e g i s t r a t i o n E r r o r :) name : r e g i s t r a t i o n F a i l e d object : nil ];
11
}
registration:
Il metodo è collegato alla pressione del pulsante Registrazione; esso si occupa
di controllare tutti i valori in ingresso e in seguito di notificare l’avvenuta
registrazione, oppure di notificare gli errori d’inserimento dati (Fig. 6.13a6.13a).
12
- ( IBAction ) registration :( id ) sender {
13
BOOL vName = ![ _name . text is Eq u al To S tr in g : @ " " ];
14
BOOL vLastName = ![ _lastName . text i s Eq u al To S tr in g : @ " " ];
15
BOOL vMail = ![ _mail . text is Eq u al To S tr in g : @ " " ];
16
BOOL vPassword1 = ![ _password1 . text i sE qu a lT oS t ri n g : @ " " ];
17
BOOL vPassword2 = ![ _password2 . text i sE qu a lT oS t ri n g : @ " " ];
18
BOOL vEqual Passwo rd = ([ _password1 . text i sE qu a lT oS t ri n g : _password2 . text
]) && ( vPassword1 ) ;
19
NSLog ( @ " Registrazione " ) ;
69
70
20
4. Implementazione
[ _activity start Animat ing ];
21
22
if ( vName && vLastName && vMail && vPassword1 && vEqua lPassw ord ) {
23
NSString * name = _name . text ;
24
NSString * lastName = _lastName . text ;
25
NSString * email = _mail . text ;
26
NSString * password = _password1 . text ;
27
FogRequest * req = [[ FogRequest alloc ] init ];
28
[ req r e g i s t r a t i o n W i t h E m a i l : email name : name lastName : lastName
andPassword : password ];
29
30
31
[ self hideKeyboard ];
} else {
UIColor * lightYellow = [ UIColor colorWithRed :1 green :0.925 blue
:0.478 alpha :1];
32
NSLog ( @ " Errore login : Dati mancanti " ) ;
33
N SM ut a bl eS t ri n g * advice = [[ N SM u ta b le St r in g alloc ] init ];
34
[ advice appendString : @ " Inserire : " ];
35
if (! vName ) {
[ _name s e t B a c k g r o u n d C o l o r : lightYellow ];
36
[ advice appendString : @ " Nome " ];
37
38
} else {
[ _name s e t B a c k g r o u n d C o l o r : [ UIColor whiteColor ]];
39
40
}
41
if (! vLastName ) {
[ _lastName s e t B a c k g r o u n d C o l o r : lightYellow ];
42
[ advice appendString : @ " Cognome " ];
43
44
} else {
[ _lastName s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
45
46
}
47
if (! vMail ) {
[ _mail s e t B a c k g r o u n d C o l o r : lightYellow ];
48
[ advice appendString : @ " Mail " ];
49
50
} else {
[ _mail s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
51
52
}
53
if (! vPassword1 ) {
[ _password1 s e t B a c k g r o u n d C o l o r : lightYellow ];
54
[ advice appendString : @ " Password " ];
55
56
} else {
[ _password1 s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
57
58
}
59
if (! vPassword2 ) {
[ _password2 s e t B a c k g r o u n d C o l o r : lightYellow ];
60
61
} else {
[ _password2 s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
62
63
}
64
[ advice appendString : @ " .\ n " ];
4.3 Client
71
if (! vEqua lPassw ord ) {
65
66
[ _password1 s e t B a c k g r o u n d C o l o r : lightYellow ];
67
[ _password2 s e t B a c k g r o u n d C o l o r : lightYellow ];
[ advice setString : @ " Password Diverse . " ];
68
} else {
69
[ _password1 s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
70
[ _password2 s e t B a c k g r o u n d C o l o r :[ UIColor whiteColor ]];
71
}
72
73
_ r e g i s t r a t i o n I n f o . text = advice ;
74
// _ i n f o R e g i s t r a t i o n . text = @ " Username o Password Mancanti ";
[ _activity stopAnimating ];
75
}
76
77
}
registrationSuccess:
Il metodo viene richiamato dall’Observer nel momento in cui viene notificata
l’avvenuta Registrazione dell’Utente. Esso si occupa di chiudere la View e
notificare l’Utente con un Alert adeguato (Figura 6.12b).
78
- ( void ) r e g i s t r a t i o n S u c c e s s : ( NSNot ificat ion *) notification {
79
// essential for istant message on main queue
80
dis patch_ async ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
81
_ r e g i s t r a t i o n I n f o . text = @ " Registrazione Effettuata . " ;
82
[ _activity stopAnimating ];
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle : @ " Fog
83
Escaping " message : @ " Registrazione Effettuata . " delegate : nil
c a n c e l B u t t o n T i t l e : @ " OK " o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
84
}) ;
85
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
86
87
}
4.3.5
registrationError:
Il metodo viene richiamato dall’Observer, nel momento in cui viene notificato
un errore di Registrazione. Esso si occupa di far visualizzare direttamente
nella View, un messaggio di errore Registrazione.
88
- ( void ) r e g i s t r a t i o n E r r o r : ( NS Notifi cation *) notification {
89
// essential for istant message on main queue
90
dis patch_ async ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
72
4. Implementazione
NSLog ( @ " Errore registration " ) ;
91
92
_ r e g i s t r a t i o n I n f o . text = @ " Errore di Registrazione " ;
93
[ _activity stopAnimating ];
}) ;
94
95
}
4.3.6
FogGeoTagViewController
FogGeoTagViewController è la classe imputata alla gestione grafica dell’inserimento del dato ambientale di Nebbia. Nell’interfaccia grafica è presente
il pulsante Invia; se premuto, richiamerà il metodo per l’inserimento della
Segnalazione. L’interfaccia contiene la Property necessaria alla gestione del
Picker.
1
# import < UIKit / UIKit .h >
2
3
@interface F o g G e o T a g V i e w C o n t r o l l e r : U I V i e w C o n t r o l l e r
4
@property ( strong , nonatomic ) IBOutlet UIPickerView * v i s i b i l i t y P i c k e r ;
5
6
@end
viewDidLoad:
viewDidLoad si assicura, che nel momento del caricamento della View, vengano inseriti tutti i valori di visibilità nel Picker.
1
- ( void ) viewDidLoad
2
{
3
[ super viewDidLoad ];
4
_ v i s i b i l i t y P i c k e r . dataSource = self ;
5
_ v i s i b i l i t y P i c k e r . delegate = self ;
6
visi bility Name = @ [ @ " Limpido " , @ " Caligine >10 Km " ,
7
@ " 1 Km < Foschia <10 Km " ,@ " Nebbia Spessa ( max 200 mt ) " ,
@ " 30 mt < Nebbia Fitta <50 mt " ,@ " 0 mt < Nebbia Densa <30 mt " ];
8
9
}
4.3 Client
sendFogValue:
sendFogValue, si occupa di richiamare il metodo per l’inserimento del dato
ambientale di Nebbia. Nel caso che il device sia iPhone, viene chiusa la View
e si ritorna alla precedente.
10
- ( IBAction ) sendFogValue :( id ) sender {
NSN otific ation * fogValue = [ NS Notifi cation n o t i f i c a t i o n W i t h N a m e : @ "
11
fogValue " object :[ NSNumber numberWithInt : selected ]];
[[ N S N o t i f i c a t i o n Q u e u e defaultQueue ] e n q u e u e N o t i f i c a t i o n : fogValue
12
postingStyle : NSPostNow ];
13
// If iPhone , make dismiss for modal segue
14
if ([[ UIDevice currentDevice ]. model rangeOfString : @ " iPhone " ]. location !=
NSNotFound ) {
15
// Device is iPhone
16
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
}
17
18
}
4.3.7
EscapeFromFogViewController
EscapeFromFogViewController, è la classe che si occupa di gestire la grafica
per la richiesta di un percorso alternativo. L’interfaccia dichiara le Property
necessarie per la gestione dei componenti grafici e un metodo pubblico che
verrà utilizzato per fare il Geocoding della posizione attuale dell’Utente, nel
momento del caricamento della View.
1
# import < UIKit / UIKit .h >
2
# import < CoreLocation / CoreLocation .h >
3
4
@interface E s c a p e F r o m F o g V i e w C o n t r o l l e r : U I V i e w C o n t r o l l e r
5
@property ( strong , nonatomic ) IBOutlet UITextField * star tTextF ield ;
6
@property ( strong , nonatomic ) IBOutlet UITextField * a r ri ve T ex t Fi el d ;
7
@property ( strong , nonatomic ) IBOutlet UILabel * startLabel1 ;
8
@property ( strong , nonatomic ) IBOutlet UILabel * startLabel2 ;
9
@property ( strong , nonatomic ) IBOutlet UILabel * startLabel3 ;
10
@property ( strong , nonatomic ) IBOutlet UILabel * arriveLabel1 ;
11
@property ( strong , nonatomic ) IBOutlet UILabel * arriveLabel2 ;
12
@property ( strong , nonatomic ) IBOutlet UILabel * arriveLabel3 ;
13
- ( void ) s e t U s e r P o s i t i o n P l a c e M a r k :( CLLocation *) location ;
14
@property ( strong , nonatomic ) IBOutlet U I A c t i v i t y I n d i c a t o r V i e w *
startActivityIndicator ;
73
74
4. Implementazione
15
@property ( strong , nonatomic ) IBOutlet U I A c t i v i t y I n d i c a t o r V i e w *
16
@end
arriveActivityIndicator ;
Variabili d’istanza
Sono necessarie alcune variabili d’istanza, che sono definite nell’implementazione dell’interfaccia.
1
# import " E s c a p e F r o m F o g V i e w C o n t r o l l e r . h "
2
3
@interface E s c a p e F r o m F o g V i e w C o n t r o l l e r () < UITextFieldDelegate >
4
@property ( nonatomic , strong ) N SMutab leArra y * placeResults ;
5
@property ( nonatomic , strong ) CLPlacemark * userPlacemark ;
6
@property ( nonatomic , strong ) CLLocation * startLocation ;
7
@property ( nonatomic , strong ) CLLocation * a rriveL ocatio n ;
8
@end
viewDidLoad:
Al caricamento della View, sono impostate le label che saranno utilizzate per
visualizzare le informazioni, sul punto di partenza e di arrivo. Viene inoltre
impostata la classe come Delegate per le TextField, dove saranno inseriti i
punti di partenza e arrivo.
9
10
- ( void ) viewDidLoad
{
11
[ super viewDidLoad ];
12
_ st ar t Te xt F ie l d . delegate = self ;
13
_ a r r i v e T e x t F i e l d . delegate = self ;
14
_arriveLabel1 . text = @ " " ;
15
_arriveLabel2 . text = @ " " ;
16
_arriveLabel3 . text = @ " " ;
17
_startLabel1 . text = @ " " ;
18
_startLabel2 . text = @ " " ;
_startLabel3 . text = @ " " ;
19
20
}
4.3 Client
75
escape:
Il metodo escape, controlla i dati inseriti dall’utente e ne verifica la correttezza; nel caso superi il controllo, sarà inviata una Notification contenente
i punti di partenza e arrivo. La Notification sarà poi presa in carica, da
RoutePlanningViewController.
21
- ( IBAction ) escape :( id ) sender {
22
if ( _st artLoc ation && _ ar r iv e Lo ca t io n ) {
23
if ([ _ startL ocatio n d i s t a n c e F r o m L o c a t i o n : _a r ri v eL oc a ti on ] < 55000) {
24
// escape from fog
25
NSArray * locations = [ NSArray a r r a y W i t h O b j e c t s : _startLocation ,
26
_arriveLocation , nil ];
NSN otific ation * escape = [ NSNot ificat ion n o t i f i c a t i o n W i t h N a m e : @ "
27
escape " object : locations ];
// Posso scegliere anche una queue diversa
28
[[ N S N o t i f i c a t i o n Q u e u e defaultQueue ] e n q u e u e N o t i f i c a t i o n : escape
29
postingStyle : NS PostWh enIdle ];
// If iPhone , make dismiss for modal segue
30
if ([[ UIDevice currentDevice ]. model rangeOfString : @ " iPhone " ].
31
location != NSNotFound ) {
32
// Device is iPhone
33
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
}
34
} else {
35
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle : @ " Fog
36
Escaping " message : @ " Distanza maggiore di 55 Km , non permesso . " delegate :
nil c a n c e l B u t t o n T i t l e : @ " OK " o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
37
}
38
} else {
39
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle : @ " Fog
40
Escaping " message : @ " Errore \ nInserisci tutti i campi ! " delegate : nil
c a n c e l B u t t o n T i t l e : @ " OK " o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
41
}
42
43
}
cancel:
Il metodo si occupa di chiudere la View, per ritornare alla precedente. Questo
metodo è utilizzato solo dai device iPhone.
76
45
4. Implementazione
- ( IBAction ) cancel :( id ) sender {
[ self d i s m i s s V i e w C o n t r o l l e r A n i m a t e d : YES completion : nil ];
46
47
}
textFieldShouldReturn:
Rappresenta uno dei metodi Delegate della TextField. Viene richiamato alla
pressione del pulsante invio, sulla tastiera del Sistema Operativo. Il metodo
si occupa di creare delle descrizioni per il punto di partenza e arrivo, da
inserire direttamente nella View come controllo visivo per l’Utente. Verrà
quindi richiamato il metodo di classe geocodeAddress:forDestination, che si
occuperà di generare queste informazioni.
48
- ( BOOL ) t e x t F i e l d S h o u l d R e t u r n :( UITextField *) textField {
49
NSString * destination = nil ;
50
if ([ textField isEqual : _ s ta rt T ex tF i el d ]) {
// start text field is editing
51
destination = @ " start " ;
52
} else {
53
// arrive text field is editing
54
destination = @ " arrive " ;
55
56
}
57
NSLog ( @ " Text should change " ) ;
58
[ self geocod eAddre ss : textField . text for Destin ation : destination ];
59
NSLog ( @ " Text should return " ) ;
60
[ textField r e s i g n F i r s t R e s p o n d e r ];
return YES ;
61
62
}
textFieldShouldClear:
Rappresenta il secondo metodo Delegate della TextField. Viene richiamato
nel momento in cui si preme la x a lato della TextField. Il metodo si occupa
di ripristinare il contenuto delle label riguardanti l’inserimento del punto di
partenza o di arrivo.
63
- ( BOOL ) t e x t F i e l d S h o u l d C l e a r :( UITextField *) textField {
64
NSLog ( @ " Text should clear " ) ;
65
if ([ textField isEqual : _ s ta rt T ex tF i el d ]) {
4.3 Client
77
66
// start text field clearing
67
_startLabel1 . text = @ " " ;
68
_startLabel2 . text = @ " " ;
_startLabel3 . text = @ " " ;
69
} else {
70
71
// arrive text field clearing
72
_arriveLabel1 . text = @ " " ;
73
_arriveLabel2 . text = @ " " ;
_arriveLabel3 . text = @ " " ;
74
}
75
return YES ;
76
77
}
geocodeAddress:forDestination:
Il metodo viene utilizzato per ricavare le informazioni di localizzazione, su
una stringa passata in ingresso. Viene effettuata la richiesta all’oggetto
CLGeocoder, che restituirà le descrizioni relative.
78
- ( void ) geoco deAddr ess :( NSString *) address f orDest inatio n :( NSString *)
destination {
if (! _placeResults ) _placeResults = [[ NSMu tableA rray alloc ] init ];
79
[[ UIApplication s h a r e d A p p l i c a t i o n ] s e t N e t w o r k A c t i v i t y I n d i c a t o r V i s i b l e :
80
YES ];
if ([ destination i sE qu a lT oS t ri ng : @ " arrive " ]) {
81
[ _ a r r i v e A c t i v i t y I n d i c a t o r startA nimati ng ];
82
} else {
83
[ _ s t a r t A c t i v i t y I n d i c a t o r s tartAn imatin g ];
84
85
}
86
[ _placeResults r e m o v e A l l O b j e c t s ];
87
CLGeocoder * geocoder = [[ CLGeocoder alloc ] init ];
88
[ geocoder g e o c o d e A d d r e s s S t r i n g : address
c o m p l e t i o n H a n d l e r :^( NSArray * placemarks , NSError * error ) {
89
90
for ( CLPlacemark * aPlacemark in placemarks )
91
{
[ _placeResults addObject : aPlacemark ];
92
93
}
94
// load results into Lable
95
if ([ _placeResults count ] >0) {
CLPlacemark * place = _placeResults [0];
96
[ self p r i n t P l a c e M a r k I n t o V i e w : place andD estina tion
97
: destination ];
}
98
}];
99
100
}
78
4. Implementazione
printPlaceMarkIntoView:
Il metodo si occupa di prendere in ingresso gli oggetti CLPlacemark rappresentanti le informazioni riguardanti il punto di partenza e di arrivo. Le
informazioni sono quindi inserite all’interno delle label relative, e visualizzate
all’interno della View.
102
- ( void ) p r i n t P l a c e M a r k I n t o V i e w :( CLPlacemark *) place andD estina tion :(
NSString *) destination {
103
C L L o c a t i o n C o o r d i n a t e 2 D loc = place . location . coordinate ;
104
NSDictionary * dict = place . a d d r e s s D i c t i o n a r y ;
105
NSArray * f o r m a t t e d A d d r e s s = dict [ @ " F o r m a t t e d A d d r e s s L i n e s " ];
106
N SM ut a bl eS t ri n g * a d d r e s s F o r m a t t e d = [ @ " " mutableCopy ];
107
if ([ f o r m a t t e d A d d r e s s count ] >0) {
108
a d d r e s s F o r m a t t e d = [ f o r m a t t e d A d d r e s s [0] mutableCopy ];
109
for ( int i =1; i <[ f o r m a t t e d A d d r e s s count ]; i ++) {
[ a d d r e s s F o r m a t t e d appendString :[ NSString s t r i n g W i t h F o r m a t : @ " , % @
110
" , f o r m a t t e d A d d r e s s [ i ]]];
}
111
112
}
113
if ([ destination is E qu al T oS t ri ng : @ " arrive " ]) {
114
[ _ a r r i v e A c t i v i t y I n d i c a t o r stopAnimating ];
115
_arriveLabel1 . text = a d d r e s s F o r m a t t e d ;
116
_arriveLabel2 . text = place . a d d r e s s D i c t i o n a r y [ @ " State " ];
117
_arriveLabel3 . text = geoInfo ;
_ ar ri v eL oc a ti o n = place . location ;
118
} else {
119
120
[ _ s t a r t A c t i v i t y I n d i c a t o r stopAnimating ];
121
_startLabel1 . text = a d d r e s s F o r m a t t e d ;
122
_startLabel2 . text = place . a d d r e s s D i c t i o n a r y [ @ " State " ];
123
_startLabel3 . text = geoInfo ;
_st artLoc ation = place . location ;
124
}
125
[[ UIApplication s h a r e d A p p l i c a t i o n ] s e t N e t w o r k A c t i v i t y I n d i c a t o r V i s i b l e : NO
126
];
127
}
4.3.8
Grid
L’Oggetto Grid, rappresenta la griglia che viene creata per la ricerca di un
percorso alternativo. La sua interfaccia dichiara i metodi pubblici necessari
al funzionamento.
4.3 Client
128
@interface Grid : NSObject
129
- ( id ) i n i t G r i d W i t h R o u t e :( NSArray *) route ;
130
- ( NSArray *) getGridPoints ;
131
- ( NSDictionary *) g e t G r i d D i c t i o n a r y ;
132
- ( NSArray *) findSolutions ;
133
- ( void ) gridReady :( NSDictionary *) grid ;
134
@end
Variabili d’Istanza
Sono importate molte Librerie, tra le quali è presente PESGraph, per il
calcolo dell’algoritmo di Dijskra. Sono inoltre dichiarate le variabili necessarie
per la configurazione dei vari stati, che può assumere la classe.
135
# import " Grid . h "
136
# import " RoutePoint . h "
137
# import " ControlPoint . h "
138
# import " FogRequest . h "
139
# import < CoreLocation / CoreLocation .h >
140
# import < MapKit / MapKit .h >
141
142
# import " PESGraph . h "
143
# import " PESGraphNode . h "
144
# import " PESGraphEdge . h "
145
# import " PESGraphRoute . h "
146
# import " P E S G r a p h R o u t e S t e p . h "
147
148
@interface Grid ()
149
@property ( nonatomic , strong ) NS Mutabl eArray * c o n t r o l P o i n t s I n R o u t e s ;
150
@property ( nonatomic , strong ) N S M u t a b l e D i c t i o n a r y * gridDi ctiona ry ;
151
@property ( nonatomic , strong ) CLLocation * startLocation ;
152
@property ( nonatomic , strong ) CLLocation * ar r iv al L oc a ti on ;
153
@property ( nonatomic , strong ) NS Mutabl eArray * solutionSteps ;
154
@end
155
156
@ im pl e me nt a ti on Grid {
157
int M A X _ D I S T A N C E _ B E T W E E N _ P O I N T S ;
158
int MULTIPLIER ;
159
int maxRow ;
160
int maxColumn ;
161
int d is ta n ce Co u nt e r ;
162
int a ct ua l Ke yN u mb e r ;
163
NSArray * allKeys ;
164
NSString * a r r i v a l P o i n t I n G r i d ;
79
80
4. Implementazione
NSString * s t a r t P o i n t I n G r i d ;
165
166
}
initGridWithRoute:
Viene creato un metodo per l’inizializzazione delle variabili necessarie all’oggetto. Viene richiamato il metodo di classe calculateBoundsPointsWithRoute,
che calcolerà i punti rappresentanti i margini esterni della griglia (Figura 3.1);
viene inoltre richiamato il metodo createControlPointsGridWithBounds, che
si occupa di creare tutti i Punti di Controllo all’interno dei margini esterni
(Figura 3.2). Dopo aver creato la griglia dei Punti di Controllo, viene richiamato il metodo requestFogData, che si occupa di richiedere i dati sulle Nebbie
per i Punti di Controllo.
168
- ( id ) i n i t G r i d W i t h R o u t e :( NSArray *) route {
self = [ super init ];
169
170
M A X _ D I S T A N C E _ B E T W E E N _ P O I N T S = 2000; // 2 km standard distance
171
MULTIPLIER = 1;
172
maxRow = -1;
173
maxColumn = -1;
174
d is ta n ce Co u nt e r = 0;
_ c o n t r o l P o i n t s I n R o u t e s = [[ self c a l c u l a t e B o u n d s P o i n t s W i t h R o u t e : route ]
175
mutableCopy ];
_ c o n t r o l P o i n t s I n R o u t e s = [[ self c r e a t e C o n t r o l P o i n t s G r i d W i t h B o u n d s :
176
_ c o n t r o l P o i n t s I n R o u t e s andRoute : route ] mutableCopy ];
177
allKeys = [ _g ri d Di ct i on a ry allKeys ]; // important here
178
[ self reques tFogDa ta ];
return self ;
179
180
}
requestFogData:
Il metodo richiama l’oggetto FogRequest che si occuperà di generare una
richiesta HTTP per la griglia dei Punti di Controllo.
181
- ( void ) reque stFogD ata {
182
FogRequest * fogReq = [[ FogRequest alloc ] init ];
183
[ fogReq r e q u e s t D e n s i t y O f F o g W i t h G r i d : _ g ri d Di ct i on ar y ];
184
}
4.3 Client
81
gridReady:
Quando il Server risponderà alla richiesta effettuata tramite l’oggetto FogRequest, verrà richiamato il seguente metodo. Esso si occupa di inserire i
dati ambientali di Nebbia ricevuti, all’interno della libreria PESGraph per il
calcolo della soluzione.
4.3.9
insertAllGridIntoDijskraAlgorithm
In questo metodo, viene fatto il lavoro più delicato; cioè inserire i pesi degli
archi diretti ai nodi adiacenti. Viene seguito il ragionamento presente nel
Capitolo 3.4.
Per il calcolo dell’algoritmo di Dijskra, viene utilizzata la libreria PESGraph;
essa prende in ingresso il nome dell’arco (riga 195), e il peso dello stesso (riga
205). Quando per ogni nodo sono salvate le informazioni sul peso degli archi
diretti ai nodi adiacenti, inizia il calcolo della soluzione (riga 213).
185
186
- ( void ) i n s e r t A l l G r i d I n t o D i j s k r a A l g o r i t h m {
// insert the grid
187
PESGraph * graph = [[ PESGraph alloc ] init ];
188
// add all the weight to the graph ’s point
189
for ( NSString * key in allKeys ) {
190
ControlPoint * cp = _g ri d Di ct i on a ry [ key ];
191
// find distance from up point
192
if (([ cp . rowNumber intValue ] -1) >= 0) {
193
NSString * upKey = [ NSString s t r i n g W i t h F o r m a t : @ " %d -% d " ,[ cp .
rowNumber intValue ] -1 ,[ cp . colNumber intValue ]];
194
ControlPoint * up = [ _g r id D ic ti o na ry objectForKey : upKey ];
195
NSString * bidirectional = [ NSString s t r i n g W i t h F o r m a t : @ " % @ <--> %
@ " ,key , upKey ];
196
int fogLevel = 0;
197
if ([ cp . levelOfFog intValue ] >[ up . levelOfFog intValue ]) {
fogLevel = ([ cp . levelOfFog intValue ]* fogMultiplier ) +
198
r ou te M ul ti p li e r ;
199
} else {
fogLevel = ([ up . levelOfFog intValue ]* fogMultiplier ) +
200
r ou te M ul ti p li e r ;
201
}
202
cp . upFogValue = [ NSNumber numberWithInt : fogLevel -1];
203
PESGraphNode * n1 = [ PESGraphNode n o d e W i t h I d e n t i f i e r : key ];
204
PESGraphNode * n2 = [ PESGraphNode n o d e W i t h I d e n t i f i e r : upKey ];
82
4. Implementazione
[ graph a d d B i D i r e c t i o n a l E d g e :[ PESGraphEdge edgeWithName :
205
bidirectional andWeight :[ NSNumber numberWithInt : fogLevel ]] fromNode : n1
toNode : n2 ];
}
206
.... ( Molto simile per ognuno dei punti di adiacenza )
207
}
208
PESGraphNode * startNode = [ graph n o d e I n G r a p h W i t h I d e n t i f i e r :
209
s t a r t P o i n t I n G r i d ];
PESGraphNode * arrivalNode = [ graph n o d e I n G r a p h W i t h I d e n t i f i e r :
210
a r r i v a l P o i n t I n G r i d ];
if ( arrivalNode && startNode ) {
211
PESGraphRoute * route = [ graph s h o r t e s t R o u t e F r o m N o d e : startNode toNode
212
: arrivalNode ];
NSArray * steps = route . steps ;
213
_so lution Steps = [[ NSMu tableA rray alloc ] i n i t W i t h C a p a c i t y :[ steps
214
count ]];
for ( P E S G r a p h R o u t e S t e p * graphStep in steps ) {
215
216
PESGraphNode * stepNode = graphStep . node ;
217
[ _s olutio nSteps addObject : _ gr id D ic ti o na r y [ stepNode . identifier ]];
}
218
}
219
220
}
4.3.10
FogRequest
L’oggetto FogRequest, è imputato alla generazione delle richieste HTTP verso
il Server. FogRequest ha la particolarità d’implementare il pattern Singleton;
esso permette di avere un’unica istanza della classe, con benefici sulle prestazioni. Descriverò solo i metodi per l’inserimento della segnalazione di
Nebbia e di ricerca del percorso alternativo, questo perché per il login e la
registrazione, non c’è nulla di sostanzialmente diverso.
L’interfaccia descrive i metodi pubblici che sono implementati.
1
# import < Foundation / Foundation .h >
2
# import < CoreLocation / CoreLocation .h >
3
4
@interface FogRequest : NSObject
5
- ( void ) r e q u e s t D e n s i t y O f F o g W i t h G r i d :( N S M u t a b l e D i c t i o n a r y *) grid ;
6
- ( void ) r e g i s t r a t i o n W i t h E m a i l :( NSString *) email name :( NSString *) name
7
- ( void ) login WithEm ail :( NSString *) email andPassword :( NSString *) password ;
8
- ( void ) i n s e r t F o g D a t a W i t h C o o r d i n a t e :( C L L o c a t i o n C o o r d i n a t e 2 D ) point
lastName :( NSString *) lastName andPassword :( NSString *) password ;
andFogValue :( int ) fogValue ;
4.3 Client
9
10
+ ( FogRequest *) sh aredIn stance ; // singleton
@end
Variabili d’Istanza
Oltre alle variabili necessarie per la memorizzazione della griglia e della soluzione, viene definita la stringa che sarà utilizzata per le richieste HTTP
secondo il protocollo di comunicazione (Cap. 4.1.3).
11
# import " FogRequest . h "
12
# import " ControlPoint . h "
13
# import " RoutePoint . h "
14
15
# define SERVER_PATH @ " http :// fogescaping . esy . es / request . php ? service = "
16
17
@interface FogRequest ()
18
@property ( nonatomic , strong ) N S M u t a b l e D i c t i o n a r y * gridDi ctiona ry ;
19
@property ( nonatomic , strong ) N S M u t a b l e D i c t i o n a r y * r ou te D ic t io na r y ;
20
@end
Implementazione Singleton
I metodi sottostanti garantiscono una corretta implementazione del pattern
Singleton.
21
# pragma mark - shared instance for singleton
22
+ ( FogRequest *) sh aredIn stance {
23
static d i sp at c h_ on c e_ t pred ;
24
static FogRequest * shared = nil ;
25
dispatch_once (& pred , ^{
shared = [[ super alloc ] init ];
26
}) ;
27
return shared ;
28
29
}
30
31
- ( id ) copyWithZone :( NSZone *) zone {
return self ;
32
33
}
83
84
4. Implementazione
requestDensityOfFogWithGrid:
Il metodo prende in ingresso un Array rappresentante la griglia dei Punti
di Controllo, per il quale fare la richiesta dei dati ambientali. Successivamente viene costruito un JSON conforme al protocollo di comunicazione (Listing:4.10) e viene richiamato il metodo di classe getFogDataForGridJson.
34
- ( void ) r e q u e s t D e n s i t y O f F o g W i t h G r i d :( N S M u t a b l e D i c t i o n a r y *) grid {
35
_ gr id D ic ti o na r y = grid ;
36
NSArray * keys = [ grid allKeys ];
37
38
NSM utable Array * gridArray = [[ NSMu tableA rray alloc ] init ];
39
// create a grid json with control point information
40
for ( NSString * key in keys ) {
ControlPoint * cp = grid [ key ];
41
42
N S M u t a b l e D i c t i o n a r y * dict = [[ N S M u t a b l e D i c t i o n a r y alloc ] init ];
43
[ dict setObject :[ NSNumber n um b er Wi t hF lo a t : cp . location . coordinate .
latitude ] forKey : @ " lat " ];
[ dict setObject :[ NSNumber n um b er Wi t hF lo a t : cp . location . coordinate .
44
longitude ] forKey : @ " lng " ];
[ dict setObject : key forKey : @ " point_id " ];
45
[ gridArray addObject : dict ];
46
}
47
NSDictionary * gridToSend = [[ NSDictionary alloc ] i n i t W i t h O b j e c t s A n d K e y s :
48
gridArray , @ " points " , nil ];
49
NSData * jsonData = [ self t r a n s f o r m D i c t i o n a r y I n t o J s o n : gridToSend ];
50
[ self g e t F o g D a t a F o r G r i d J s o n : jsonData ];
51
}
getFogDataForGridJson
Il metodo permette di inviare una richiesta asincrona al servizio checkForFogValues. Quando arriverà la risposta, essa sarà gestita dal completionHandler
che invierà la Notification adeguata. La Notification sarà gestita dalla classe
RoutePlanningViewController.
52
53
- ( void ) g e t F o g D a t a F o r G r i d J s o n :( NSData *) requestData {
NSString * urlAsString = [ NSString s t r i n g W i t h F o r m a t : @ " % @ c h e c k F o r F o g V a l u e s
" , SERVER_PATH ];
54
NSURL * url = [ NSURL URLWithString : urlAsString ];
55
N S M u t a b l e U R L R e q u e s t * request = [ N S M u t a b l e U R L R e q u e s t r equest WithUR L : url ];
4.3 Client
85
56
[ request setHTTPMethod : @ " POST " ];
57
[ request setValue : @ " application / json " f o r H T T P H e a d e r F i e l d : @ " Accept " ];
58
[ request setValue : @ " application / json " f o r H T T P H e a d e r F i e l d : @ " Content - Type "
];
[ request setValue :[ NSString s t r i n g W i t h F o r m a t : @ " % lu " , ( unsigned long ) [
59
requestData length ]] f o r H T T P H e a d e r F i e l d : @ " Content - Length " ];
[ request setHTTPBody : requestData ];
60
61
N S O p e r a t i o n Q u e u e * queue = [[ N S O p e r a t i o n Q u e u e alloc ] init ];
62
63
[ NS U RL Co n ne ct i on s e n d A s y n c h r o n o u s R e q u e s t : request queue : queue
64
c o m p l e t i o n H a n d l e r :^( NSURLResponse * response ,
65
NSData * data , NSError * error ) {
if ([ data length ] >0 && error == nil ) {
66
[ self s e t F o g D a t a I n G r i d : data ];
67
68
}
69
else if ([ data length ] == 0 && error == nil ) {
// send a notification when server response is empty
70
NSN otific ation * serverError = [ NSN otific ation
71
n o t i f i c a t i o n W i t h N a m e : @ " server - error " object : nil ];
[[ N S N o t i f i c a t i o n Q u e u e defaultQueue ] e n q u e u e N o t i f i c a t i o n :
72
serverError postingStyle : NSPostNow ];
73
}
74
else if ( error != nil ) {
// send a notification for connection error
75
NSN otific ation * co nn e ct io n Er ro r = [ NSN otific ation
76
n o t i f i c a t i o n W i t h N a m e : @ " connection - error " object : nil ];
[[ N S N o t i f i c a t i o n Q u e u e defaultQueue ] e n q u e u e N o t i f i c a t i o n :
77
c on ne c ti on E rr o r postingStyle : NSPostNow ];
} }];
78
79
}
insertFogDataWithCoordinate:andFogValue:
Il metodo permette di inviare una richiesta asincrona al servizio insertFog. Viene composto un JSON conforme al protocollo di comunicazione
(Listing:4.8) e viene gestita la risposta proveniente dal Sever.
80
- ( void ) i n s e r t F o g D a t a W i t h C o o r d i n a t e :( C L L o c a t i o n C o o r d i n a t e 2 D ) point
andFogValue :( int ) fogValue {
81
82
83
// get userID from NSUSerDefault
NSDictionary * login = [[ N SUserD efault s s t a n d a r d U s e r D e f a u l t s ]
d i c t i o n a r y F o r K e y : @ " login - options " ];
86
4. Implementazione
NSString * userID = [ login objectForKey : @ " userID " ];
84
NSString * jsonRequest = [ NSString s t r i n g W i t h F o r m a t : @ " {\" userID \":\"% @
85
\" ,\" lat \":\"% f \" ,\" lng \":\"% f \" ,\" fogValue \":\"% d \"} " , userID , point .
latitude , point . longitude , fogValue ];
NSData * requestData = [ NSData dataWithBytes :[ jsonRequest UTF8String ]
86
length :[ jsonRequest length ]];
NSString * urlAsString = [ NSString s t r i n g W i t h F o r m a t : @ " % @insertFog " ,
87
SERVER_PATH ];
NSURL * url = [ NSURL URLWithString : urlAsString ];
88
89
N S M u t a b l e U R L R e q u e s t * request = [ N S M u t a b l e U R L R e q u e s t r equest WithUR L : url ];
90
[ request setHTTPMethod : @ " POST " ];
91
[ request setValue : @ " application / json " f o r H T T P H e a d e r F i e l d : @ " Accept " ];
[ request setValue : @ " application / json " f o r H T T P H e a d e r F i e l d : @ " Content - Type "
92
];
[ request setValue :[ NSString s t r i n g W i t h F o r m a t : @ " % lu " , ( unsigned long ) [
93
requestData length ]] f o r H T T P H e a d e r F i e l d : @ " Content - Length " ];
[ request setHTTPBody : requestData ];
94
95
N S O p e r a t i o n Q u e u e * queue = [[ N S O p e r a t i o n Q u e u e alloc ] init ];
96
97
[ NS U RL Co n ne ct i on s e n d A s y n c h r o n o u s R e q u e s t : request queue : queue
98
c o m p l e t i o n H a n d l e r :^( NSURLResponse * response ,
99
NSData * data , NSError * error ) {
if ([ data length ] >0 && error == nil ) {
100
disp atch_a sync ( d i s p a t c h _ g e t _ g l o b a l _ q u e u e (
101
D I SP A T C H_ Q U E U E_ P R I OR I T Y _D E F A U LT , 0) , ^{
disp atch_a sync ( d i s p a t c h _ g e t _ m a i n _ q u e u e () , ^{
102
UIAlertView * alert = [[ UIAlertView alloc ] initWithTitle :
103
@ " Fog Escaping " message : @ " Segnalazione Inviata con Successo " delegate :
nil c a n c e l B u t t o n T i t l e : @ " OK " o t h e r B u t t o n T i t l e s : nil ];
[ alert show ];
104
}) ;
105
}) ;
106
107
}
108
else if ([ data length ] == 0 && error == nil ) {
NSLog ( @ " Nothing was downloaded . " ) ; }
109
else if ( error != nil ) {
110
// send a notification for connection error
111
NSNo tifica tion * c o nn e ct io n Er ro r = [ NSNo tifica tion
112
n o t i f i c a t i o n W i t h N a m e : @ " connection - error " object : nil ];
[[ N S N o t i f i c a t i o n Q u e u e defaultQueue ] e n q u e u e N o t i f i c a t i o n :
113
c on ne c ti o nE rr o r postingStyle : NSPostNow ];
} }];
114
115
}
4.3 Client
4.3.11
CustomAnnotationPoint
L’oggetto CustomAnnotationPoint, rappresenta una annotazione sulla mappa; è stato necessario crearlo, per permettere a una annotazione di avere
alcuni valori interni che ne variassero l’aspetto grafico. Viene utilizzato per
i punti della griglia che contengono un valore di Nebbia.
L’interfaccia dichiara la Property necessaria per il valore di Nebbia; è
inoltre necessario, per la corretta visualizzazione, che la classe sia del tipo
MKPointAnnotation.
1
# import < MapKit / MapKit .h >
2
3
@interface C u s t o m P o i n t A n n o t a t i o n : M K P o i n t A n n o t a t i o n
4
5
@property ( copy ) NSNumber * fogValue ;
6
7
@end
4.3.12
ControlPoint
L’oggetto ControlPoint rappresenta un Punto di Controllo (Cap. 3.2.2). Il
ControlPoint è essenziale per la ricerca di un percorso alternativo, possiede
quindi molte variabili che saranno utilizzate in tutto il processo.
1
# import < Foundation / Foundation .h >
2
# import < CoreLocation / CoreLocation .h >
3
4
@interface ControlPoint : NSObject
5
@property ( nonatomic , assign ) int d i s t a n c e F r o m A r r i v a l ;
6
@property ( nonatomic , assign ) int d i s t a n c e F r o m S t a r t ;
7
@property ( nonatomic , assign ) int d i s t a n c e F r o m P o i n t ;
8
@property ( nonatomic , assign ) BOOL alreadyPassed ;
9
@property ( nonatomic , strong ) NSNumber * upFogValue ;
10
@property ( nonatomic , strong ) NSNumber * downFogValue ;
11
@property ( nonatomic , strong ) NSNumber * rightFogValue ;
12
@property ( nonatomic , strong ) NSNumber * LeftFogValue ;
13
@property ( nonatomic , strong ) NSNumber * u p R i g h t C o r n e r F o g V a l u e ;
14
@property ( nonatomic , strong ) NSNumber * u p L e f t C o r n e r F o g V a l u e ;
15
@property ( nonatomic , strong ) NSNumber * d o w n R i g h t C o r n e r F o g V a l u e ;
16
@property ( nonatomic , strong ) NSNumber * d o w n L e f t C o r n e r F o g V a l u e ;
17
@property ( nonatomic , strong ) NSNumber * rowNumber ;
87
88
4. Implementazione
18
@property ( nonatomic , strong ) NSNumber * colNumber ;
19
@property ( nonatomic , strong ) CLLocation * location ;
20
@property ( nonatomic , strong ) NSNumber * isPresentFog ;
21
@property ( nonatomic , strong ) NSNumber * levelOfFog ;
22
@end
L’oggetto possiede anche un metodo d’inizializzazione, che imposta i valori
prestabiliti delle Property.
1
# import " ControlPoint . h "
2
3
@ im pl e me nt a ti o n ControlPoint
4
-( id ) init {
5
self = [ super init ];
6
_levelOfFog = [ NSNumber numberWithInt :0];
7
_upFogValue = [ NSNumber numberWithInt :0];
8
_downFogValue = [ NSNumber numberWithInt :0];
_rig htFogV alue = [ NSNumber numberWithInt :0];
9
10
_LeftFogValue = [ NSNumber numberWithInt :0];
11
_ d o w n L e f t C o r n e r F o g V a l u e = [ NSNumber numberWithInt :0];
12
_ d o w n R i g h t C o r n e r F o g V a l u e = [ NSNumber numberWithInt :0];
13
_ u p L e f t C o r n e r F o g V a l u e = [ NSNumber numberWithInt :0];
14
_ u p R i g h t C o r n e r F o g V a l u e = [ NSNumber numberWithInt :0];
15
_al readyP assed = NO ;
return self ;
16
17
}
18
@end
4.3.13
Routepoint
L’oggetto RoutePoint rappresenta uno dei punti di direzione restituiti dai
servizi di direzionamento Apple. Viene utilizzato per garantire ulteriori funzionalità: sapere il livello di nebbia presente e sapere se fa parte di una
inversione a U.
1
# import < Foundation / Foundation .h >
2
# import < CoreLocation / CoreLocation .h >
3
4
@interface RoutePoint : NSObject
5
@property ( nonatomic , strong ) NSNumber * number ;
6
@property ( nonatomic , strong ) CLLocation * location ;
7
@property ( nonatomic , strong ) NSNumber * isPresentFog ;
8
@property ( nonatomic , strong ) NSNumber * levelOfFog ;
4.3 Client
9
@property ( nonatomic , strong ) NSNumber * f o g S t o p A t R o u t e P o i n t N u m b e r ;
10
@property ( nonatomic , assign ) BOOL i s A n I n v e r s i o n P o i n t ;
11
@end
Possiede un metodo d’inizializzazione che imposta i valori prestabiliti delle
Property.
1
# import " RoutePoint . h "
2
3
@ im pl e me nt a ti on RoutePoint
4
5
- ( id ) init {
6
self = [ super init ];
7
_location = nil ;
8
_isPresentFog = nil ;
9
_levelOfFog = nil ;
10
_ f o g S t o p A t R o u t e P o i n t N u m b e r = nil ;
11
_ i s A n I n v e r s i o n P o i n t = NO ;
12
return self ;
13
}
14
15
@end
4.3.14
AlternativeRouteSegment
L’oggetto rappresenta l’insieme dei punti che fanno parte di un percorso tra
un punto di soluzione e un altro. Data la natura asincrona delle richieste di
direzionamento, era necessario tenere traccia di ognuna di queste soluzioni
e successivamente unirle, per creare il percorso alternativo definitivo. L’interfaccia contiene i punti del segmento e un numero, startSolutionPoint, che
rappresenta l’ordine dello stesso rispetto al percorso totale.
1
# import < Foundation / Foundation .h >
2
3
@interface A l t e r n a t e R o u t e S e g m e n t : NSObject
4
@property ( nonatomic , strong ) NSArray * segmentPoints ;
5
@property ( nonatomic , strong ) NSNumber * s t a r t S o l u t i o n P o i n t ;
6
- ( id ) in itWith Points :( NSArray *) points a n d S t a r t S o l u t i o n P o i n t :( int )
7
@end
startSolutionPoint ;
89
90
4. Implementazione
Possiede anche un metodo d’inizializzazione che verrà richiamato per generare
ognuno di questi segmenti.
8
- ( id ) in itWith Points :( NSArray *) points a n d S t a r t S o l u t i o n P o i n t :( int )
startSolutionPoint {
self = [ super init ];
9
_se gmentP oints = points ;
10
11
_ s t a r t S o l u t i o n P o i n t = [ NSNumber numberWithInt : s t a r t S o l u t i o n P o i n t ];
12
return self ;
13
}
4.3.15
PESGraph
Per il progetto di Tesi era richiesto l’utilizzo dell’algoritmo di Dijskra, si
è voluto utilizzare una libreria molto conosciuta e ottimizzata chiamata
PESGraph. La libreria permette di creare Nodi, aggiungere Archi pesati
di connessione fra i Nodi e successivamente di calcolare il cammino minimo
con il Grafo creato dall’insieme dei Nodi.
Gli oggetti che sono presenti nella libreria sono:
• PESGraph
• PESGraphNode
• PESGraphEdge
• PESGraphRoute
• PESGraphRouteStep
La parte d’implementazione utilizzata per l’applicazione Fog Escaping è presente nella classe Grid (Cap. 4.3.8).
PESGraph
La classe permette di creare un Grafo fatto di Nodi PESGraphNode e collegati da Archi PESGraphEdge. Possiede il metodo shortestRouteFromNode:toNode: che calcola il cammino minimo all’interno del Grafo.
4.3 Client
91
PESGraphNode
Rappresenta un Nodo all’interno di un Grafo. Possiede un identificatore e
un titolo. Viene creato con il seguente codice:
1
PESGraphNode * n1 = [ PESGraphNode n o d e W i t h I d e n t i f i e r : key ];
PESGraphEdge
Rappresenta l’arco pesato tra un Nodo e un altro. Può essere inizializzato
come unidirezionale o bidirezionale. Per l’implementazione si è utilizzata
l’impostazione bidirezionale.
1
NSString * bidirectional = [ NSString s t r i n g W i t h F o r m a t : @ " % @ <--> % @ " , key ,
upKey ];
2
[ PESGraphEdge edgeWithName : bidirectional andWeight :[ NSNumber numberWithInt
: fogLevel ]] fromNode : n1 toNode : n2 ];
PESGraphRoute e PESGraphRouteStep
Rappresenta l’oggetto di ritorno dal metodo shortestRouteFromNode:toNode;
è quindi un insieme di passi PESGraphRouteStep, rappresentanti il cammino minimo all’interno del Grafo. PESGraphRouteStep rappresenta uno degli
step di soluzione, contenente i nomi dei due nodi di passaggio. Nell’implementazione i PESGraphRouteStep sono scorsi uno a uno, e inseriti nel
Dictionary delle soluzioni.
1
PESGraphRoute * route = [ graph s h o r t e s t R o u t e F r o m N o d e : startNode toNode :
arrivalNode ];
2
NSArray * steps = route . steps ;
3
_so lution Steps = [[ NSMu tableA rray alloc ] i n i t W i t h C a p a c i t y :[ steps
count ]];
4
for ( P E S G r a p h R o u t e S t e p * graphStep in steps ) {
5
PESGraphNode * stepNode = graphStep . node ;
6
[ _s olutio nSteps addObject : _ gr i dD ic t io na r y [ stepNode . identifier ]];
7
}
Capitolo 5
Studi sull’Image Recognition
Durante la fase di sviluppo, sono stati condotti alcuni test per la futura
implementazione di un sistema, capace di riconoscere automaticamente la
densità della Nebbia, in base ad alcuni scatti effettuati con i dispositivi mobili
di Apple: iPhone e iPad.
L’idea è di utilizzare tecniche di Object Recognition e Image Analysis,
assieme alla geo-localizzazione dell’Utente, per generare un valore affidabile
di visibilità. L’Utente quindi scatta una foto a un oggetto a distanza ravvicinata, poi si allontana fino a che l’applicazione non gli dice di fermarsi
e scattare un’altra foto. Il Sistema tramite la distanza, il riconoscimento
dell’oggetto e la comparazione dei livelli di colore, può trovare un valore di
visibilità affidabile.
5.1
OpenCV
Durante la fase di test sulle tecnologie è stata utilizzata la libreria OpenCV
con licenza open source BSD. La libreria offre la maggior parte delle utility
necessarie, per raggiungere gli scopi di riconoscimento oggetti ed analisi dei
fotogrammi. La libreria è nata nel 1999 come progetto di ricerca di Intel, ed
essendo cross platform, permetterebbe future implementazioni sui principali
sistemi operativi mobili (iOS e Android) oltre che su piattaforme desktop. La
93
94
5. Studi sull’Image Recognition
libreria permette con poche righe di codice di collegarsi ai sistemi di raccolta
video, e tramite alcuni filtri è possibile riconoscere e seguire oggetti come
semplici cerchi rossi durante uno stream video.
5.2
Object Recognition
I test sono stati eseguiti, per capire se era possibile fare il tracking di un
oggetto in movimento sui dispositivi mobili.
Riconoscimento di un oggetto in movimento
Per seguire un oggetto in movimento, è necessario utilizzare alcuni filtri che
permettono di isolare un determinato colore; per l’implementazione è stato scelto il rosso. Successivamente viene utilizzato il metodo HoughCircles
che permette di identificare i cerchi all’interno dello stream video filtrato.
Quando un cerchio viene identificato, viene contornato da un bordo bianco.
1
- ( void ) processImage :( Mat &) image ;
2
{
3
// red filter
4
cv :: Mat th r es ho l d_ i ma ge ;
5
cvtColor ( image , threshold_image , CV_BGRA2BGR ) ;
6
// dal rosso al rosa
7
cv :: inRange ( threshold_image , cv :: Scalar (0 , 0 , 150) , cv :: Scalar (135 , 110 ,
8
bitwise_not ( threshold_image , th re s ho ld _ im ag e ) ;
255) , t hr e sh ol d _i ma g e ) ;
9
10
GaussianBlur ( threshold_image , threshold_image , cv :: Size (3 , 3) , 2 , 2 ) ;
11
vector < Vec3f > circles ;
12
// Apply the Hough Transform to find the circles
13
HoughCircles ( threshold_image , circles , CV_HOUGH_GRADIENT , 1 ,
t hr es h ol d _i ma g e . rows /8 , 200 , 40 , 0 , 0 ) ;
14
15
NSM utable Array * circleArray = nil ;
16
// / Draw the circles detected
17
for ( size_t i = 0; i < circles . size () ; i ++ )
18
{
19
if (! circleArray ) circleArray = [[ NSMut ableAr ray alloc ]
i n i t W i t h C a p a c i t y : circles . size () ];
5.2 Object Recognition
cv :: Point center ( cvRound ( circles [ i ][0]) , cvRound ( circles [ i ][1]) ) ;
20
21
int radius = cvRound ( circles [ i ][2]) ;
22
// circle outline
23
circle ( image , center , radius , Scalar (255 ,0 ,0) , 3 , 8 , 0 ) ;
24
25
// create the mask for cropped circle
26
cv :: Mat mask = cv :: Mat :: zeros ( image . rows , image . cols , CV_8UC1 ) ;
circle ( mask , center , radius , Scalar (255 ,0 ,0) , -1 , 8 , 0 ) ; // -1
27
means filled
Mat dst ;
28
image . copyTo ( dst , mask ) ; // copy values of img to dst if mask is >
29
0.
// transform BGR to RGB
30
31
cvtColor ( dst , dst , CV_BGR2RGB ) ;
32
UIImage * img = [ self U I I m a g e F r o m C V M a t : dst ];
33
[ circleArray addObject : img ];
}
34
35
}
Com’è possibile vedere nella Figura 5.1, sono riconosciuti la maggior parte
dei cerchi rossi presenti nello stream video.
Figura 5.1: Test di Riconoscimento Oggetti.
95
96
5. Studi sull’Image Recognition
5.3
Image Analyzer
L’idea è di comparare due immagini e successivamente, dopo aver tarato adeguatamente il dispositivo, trovare in modo automatico un valore di
visibilità.
Il metodo analyzeImages carica due foto diverse, in seguito divide le foto
in tre livelli distinti, uno per colore (red-green-blue). Successivamente carica gli istogrammi e provvede a comparare i livelli con i quattro metodi a
disposizione:
• Correlation
• Chi-Square
• Intersection
• Bhattacharyya distance
1
- ( void ) analyzeImages {
2
Mat imageoneHSV , imageTwoHSV ;
3
UIImage * uiImage1 = [ UIImage imageNamed : @ " fog . jpg " ];
4
UIImage * uiImage2 = [ UIImage imageNamed : @ " fog_ultra . jpg " ];
5
_image1 . image = uiImage1 ;
6
_image2 . image = uiImage2 ;
7
Mat imageOne = [ self c v M a t F r o m U I I m a g e : uiImage1 ];
8
Mat imageTwo = [ self c v M a t F r o m U I I m a g e : uiImage2 ];
9
10
// create vector for splitted rgb
11
vector < Mat > bgr_planes1 ;
12
vector < Mat > bgr_planes2 ;
13
// Split the image in 3 places (B , G and R )
14
split ( imageOne , bgr_planes1 ) ;
15
split ( imageTwo , bgr_planes2 ) ;
16
17
// / Establish the number of bins
18
int histSize = 256;
19
// / Set the ranges ( for B ,G , R ) )
20
float range [] = { 0 , 256 } ;
21
const float * histRange = { range };
22
23
bool uniform = true ; bool accumulate = false ;
24
25
// / Histograms
5.3 Image Analyzer
26
Mat b_hist1 ;
27
Mat g_hist1 ;
28
Mat r_hist1 ;
29
Mat b_hist2 ;
30
Mat g_hist2 ;
31
Mat r_hist2 ;
32
33
34
// / Compute the histograms :
calcHist ( & bgr_planes1 [0] , 1 , 0 , Mat () , b_hist1 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
35
calcHist ( & bgr_planes1 [1] , 1 , 0 , Mat () , g_hist1 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
36
calcHist ( & bgr_planes1 [2] , 1 , 0 , Mat () , r_hist1 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
37
calcHist ( & bgr_planes2 [0] , 1 , 0 , Mat () , b_hist2 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
38
calcHist ( & bgr_planes2 [1] , 1 , 0 , Mat () , g_hist2 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
39
calcHist ( & bgr_planes2 [2] , 1 , 0 , Mat () , r_hist2 , 1 , & histSize , &
histRange , uniform , accumulate ) ;
40
41
// Draw the histograms for B , G and R
42
int hist_w = 512; int hist_h = 400;
43
int bin_w = cvRound ( ( double ) hist_w / histSize ) ;
44
45
Mat histImage1 ( hist_h , hist_w , CV_8UC3 , Scalar ( 0 ,0 ,0) ) ;
46
Mat histImage2 ( hist_h , hist_w , CV_8UC3 , Scalar ( 0 ,0 ,0) ) ;
47
48
49
// / Normalize the result
normalize ( b_hist1 , b_hist1 , 0 , histImage1 . rows , NORM_MINMAX , -1 , Mat () )
;
50
normalize ( g_hist1 , g_hist1 , 0 , histImage1 . rows , NORM_MINMAX , -1 , Mat () )
;
51
normalize ( r_hist1 , r_hist1 , 0 , histImage1 . rows , NORM_MINMAX , -1 , Mat () )
;
52
53
// / Normalize the result
normalize ( b_hist2 , b_hist2 , 0 , histImage2 . rows , NORM_MINMAX , -1 , Mat () )
;
54
normalize ( g_hist2 , g_hist2 , 0 , histImage2 . rows , NORM_MINMAX , -1 , Mat () )
;
55
normalize ( r_hist2 , r_hist2 , 0 , histImage2 . rows , NORM_MINMAX , -1 , Mat () )
;
56
57
// / Draw for each channel
58
for ( int i = 1; i < histSize ; i ++ )
59
{
60
line ( histImage1 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( b_hist1 .
97
98
5. Studi sull’Image Recognition
at < float >( i -1) ) ) ,
61
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( b_hist1 . at < float >( i ) ) ) ,
62
Scalar ( 255 , 0 , 0) , 2 , 8 , 0
);
line ( histImage1 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( g_hist1 .
63
at < float >( i -1) ) ) ,
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( g_hist1 . at < float >( i ) ) ) ,
64
Scalar ( 0 , 255 , 0) , 2 , 8 , 0
65
);
line ( histImage1 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( r_hist1 .
66
at < float >( i -1) ) ) ,
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( r_hist1 . at < float >( i ) ) ) ,
67
Scalar ( 0 , 0 , 255) , 2 , 8 , 0
68
69
);
}
70
for ( int i = 1; i < histSize ; i ++ )
71
{
line ( histImage2 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( b_hist2 .
72
at < float >( i -1) ) ) ,
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( b_hist2 . at < float >( i ) ) ) ,
73
Scalar ( 255 , 0 , 0) , 2 , 8 , 0
74
);
line ( histImage2 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( g_hist2 .
75
at < float >( i -1) ) ) ,
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( g_hist2 . at < float >( i ) ) ) ,
76
Scalar ( 0 , 255 , 0) , 2 , 8 , 0
77
);
line ( histImage2 , cv :: Point ( bin_w *( i -1) , hist_h - cvRound ( r_hist2 .
78
at < float >( i -1) ) ) ,
cv :: Point ( bin_w *( i ) , hist_h - cvRound ( r_hist2 . at < float >( i ) ) ) ,
79
Scalar ( 0 , 0 , 255) , 2 , 8 , 0
80
81
);
}
82
83
_hist1 . image = [ self U I I m a g e F r o m C V M a t : histImage1 ];
84
_hist2 . image = [ self U I I m a g e F r o m C V M a t : histImage2 ];
85
86
// print result for red compare
87
printf ( " * * * * * * * * * * * * * * * * * * * * * * * * * * * Red Compare \ n " ) ;
88
for ( int i = 0; i < 4; i ++ )
89
{ int compa re_met hod = i ;
90
double one_one = compareHist ( r_hist1 , r_hist1 , compar e_meth od ) ;
91
double one_two = compareHist ( r_hist1 , r_hist2 , compar e_meth od ) ;
92
printf ( " Method [% d ] r_one - r_one , r_one - r_two : %f , % f \ n " , i ,
93
one_one , one_two ) ;
94
}
95
// print result for green compare
96
printf ( " * * * * * * * * * * * * * * * * * * * * * * * * * * * Green Compare \ n " ) ;
97
for ( int i = 0; i < 4; i ++ )
98
{ int compa re_met hod = i ;
99
double one_one = compareHist ( g_hist1 , g_hist1 , compar e_meth od ) ;
100
double one_two = compareHist ( g_hist1 , g_hist2 , compar e_meth od ) ;
5.3 Image Analyzer
101
printf ( " Method [% d ] g_one - g_one , g_one - g_two : %f , % f \ n " , i ,
102
one_one , one_two ) ;
103
}
104
// print result for blue compare
105
printf ( " * * * * * * * * * * * * * * * * * * * * * * * * * * * Blue Compare \ n " ) ;
106
for ( int i = 0; i < 4; i ++ )
107
{ int compa re_met hod = i ;
108
double one_one = compareHist ( b_hist1 , b_hist1 , compar e_meth od ) ;
109
double one_two = compareHist ( b_hist1 , b_hist2 , compar e_meth od ) ;
110
printf ( " Method [% d ] b_one - b_one , b_one - b_two : %f , % f \ n " , i ,
111
one_one , one_two ) ;
}
112
printf ( " * * * * * * * * * * * * * * * * * * * * * * * * * * * STOP " ) ;
113
114
}
Per ogni livello di colore, viene inserito sempre un campione di test, in modo
da verificare che la comparazione fra lo stesso livello della medesima foto,
dia un valore neutrale. Il secondo valore invece rappresenta il risultato della
comparazione tra le due immagini. Com’è possibile notare, in tutti i casi e in
tutti i livelli di colore, le comparazioni danno risultati soddisfacenti. Sarebbe
quindi possibile utilizzare uno dei seguenti metodi, per comparare la prima
immagine con la seconda e capire quale livello di visibilità esiste.
1
* * * * * * * * * * * * * * * * * * * * * * * * * * * Red Compare
2
Method [0] r_one - r_one , r_one - r_two : 1.000000 , -0.303090
3
Method [1] r_one - r_one , r_one - r_two : 0.000000 , 32024 43.748 974
4
Method [2] r_one - r_one , r_one - r_two : 9907.996529 , 63.392060
5
6
Method [3] r_one - r_one , r_one - r_two : 0.000000 , 0.969744
* * * * * * * * * * * * * * * * * * * * * * * * * * * Green Compare
7
Method [0] g_one - g_one , g_one - g_two : 1.000000 , -0.290273
8
Method [1] g_one - g_one , g_one - g_two : 0.000000 , 741814.764506
9
Method [2] g_one - g_one , g_one - g_two : 15948.307584 , 170.305205
10
11
Method [3] g_one - g_one , g_one - g_two : 0.000000 , 0.960473
* * * * * * * * * * * * * * * * * * * * * * * * * * * Blue Compare
12
Method [0] b_one - b_one , b_one - b_two : 1.000000 , -0.343736
13
Method [1] b_one - b_one , b_one - b_two : 0.000000 , 8 0 8 4 8 3 7 0 4 6 8 0 . 0 7 4 0 9 7
14
Method [2] b_one - b_one , b_one - b_two : 13589.429940 , 155.564171
15
16
Method [3] b_one - b_one , b_one - b_two : 0.000000 , 0.963065
* * * * * * * * * * * * * * * * * * * * * * * * * * * STOP
99
100
5. Studi sull’Image Recognition
Figura 5.2: Test di Comparazione Immagini.
Capitolo 6
Validazione
In questo capitolo si tratteranno le metodologie utilizzate per la validazione
del progetto di Tesi. Nella prima sezione si prenderanno in considerazione
le prestazioni del sistema e nella seconda saranno effettuate alcune comparazioni con applicazioni simili. Infine saranno presentati alcuni screenshot che
rappresentano le funzionalità implementate nell’applicazione.
6.1
Prestazioni
Le prestazioni del sistema sono state monitorate in fase di debug, tramite la
piattaforma XCode 5, e successivamente tramite Instrument. Instrument è
un’applicazione che fa parte degli strumenti messi a disposizione da Apple
per lo sviluppo; permette di verificare alcuni parametri come il consumo
di batteria, la quantità di CPU utilizzata in un determinato momento e la
quantità di pacchetti scambiati con la rete.
6.1.1
Utilizzo di Memoria
All’avvio l’applicazione utilizza circa 11.2 MB di memoria, pari al 2% sulla
memoria totale. Durante la fase più impegnativa, ovvero il caricamento dei
componenti grafici sulla mappa, l’applicazione arriva a utilizzare circa 25
MB, pari al 4.9% sulla memoria totale.
101
102
6. Validazione
(a) Apertura Applicazione.
(b) Caricamento Grafica.
Figura 6.1: Timeline dell’Utilizzo di Memoria.
6.1.2
Utilizzo CPU
In fase di avvio l’applicazione carica i componenti grafici per visualizzare le
mappe, raggiunge quindi un utilizzo di CPU pari al 52.4%; successivamente
l’applicazione si stabilizzerà, rimanendo circa sul 25%. La fase più importante, inizia con la richiesta di un percorso alternativo e raggiunge il suo punto
massimo nel momento del calcolo dell’algoritmo di Dijskra, che fa registrare
un consumo dell’80% sul totale.
Figura 6.2: Test di Utilizzo CPU su iPhone.
6.1 Prestazioni
103
In Figura 6.3 vi è un elenco dei thread attivi durante la ricerca di un
percorso alternativo. I thread più importanti sono:
Thread 1 Creazione della Griglia dei Punti di Controllo;
Thread 18 Computazione dell’Algoritmo di Dijskra.
Thread 19 Richieste Asincrone HTTP;
Figura 6.3: Timeline di Vita dei Thread.
6.1.3
Consumo di Energia
Per quanto riguarda il consumo di energia, bisogna differenziare l’utilizzo
dell’applicazione con rete Wifi dall’utilizzo con rete cellulare. Come si può
notare in Figura 6.4, durante l’utilizzo della rete Wifi, solo in un punto la
richiesta di energia raggiunge un consumo di 1/20; mentre durante l’utilizzo
della rete cellulare un consumo di 1/20 si ha nella maggior parte dei casi, e
in un punto si registra un consumo di 8/20.
104
6. Validazione
Il risultato non stupisce per nulla; infatti, sia la localizzazione dell’Utente,
sia lo scambio di dati, sono più onerosi durante l’utilizzo della rete Cellulare.
(a) Uso di rete Cellulare.
(b) Uso di rete Wifi
Figura 6.4: Paragone del Consumo Energetico tra Rete Wifi e Cellulare.
6.1.4
Timeline di Esecuzione
In Figura 6.5 si possono benissimo notare i momenti diversi dell’esecuzione
dell’applicazione:
Al secondo 15, l’applicazione invia la richiesta dei dati ambientali di Nebbia
al Server. Circa dal secondo 37, l’applicazione riceve la risposta dal Server e
inizia a calcolare l’Algoritmo di Dijskra. Circa al secondo 39, l’applicazione
richiede ai servizi di direzionamento di Apple, il passaggio tra un punto e
l’altro della soluzione.
6.2 Comparazioni
105
Figura 6.5: Test prestazioni su iPhone con rete wifi.
6.2
Comparazioni
Fog Escaping è stato confrontato con alcuni sistemi che utilizzano GPS, mappe e sistema di navigazione. Bisogna però far notare che ognuna delle applicazioni che è stata confrontata, utilizza un sistema di direzionamento completamente lato Server; mentre Fog Escaping, crea un percorso utilizzando
un algoritmo che è a carico quasi solamente del device.
La comparazione è stata eseguita con l’applicazione Instrument tramite
il dispositivo iPhone 4s. Sono lanciate le applicazioni una alla volta e per
ognuna di esse viene richiesta una navigazione o una visualizzazione di dati
sulla mappa.
106
6. Validazione
Figura 6.6: Comparazione con Instrument.
6.2.1
Comparazione con Waze
Waze è un’applicazione con paradigma Data Crowd-Sourcing, dove gli utenti
si scambiano informazioni riguardanti il traffico. L’utilizzo di CPU di Waze
è in media più oneroso di Fog Escaping; ma mentre Fog Escaping raggiunge
un picco dell’80%, Waze rimane stabile tra il 40-60%. Questo è sicuramente
imputabile alla grafica più onerosa e a un sistema di direzionamento che
opera lato Server.
Durante l’esecuzione non si sono verificati Memory Warning (Sovraccarichi
della memoria).
6.2 Comparazioni
107
Figura 6.7: Utilizzo CPU di Waze.
6.2.2
Comparazione con OpenSignal
OpenSignal è un’applicazione con paradigma di Data Crowd-Sourcing, dove
gli Utenti possono segnalare lo stato di ricezione della rete cellulare. L’utilizzo di CPU di OpenSignal è decisamente maggiore di Fog Escaping, infatti,
raggiunge un picco del 95%; inoltre durante questo picco viene notificato un
Memory Warning, che indica chiaramente come il programma non sia stato
ottimizzato.
108
6. Validazione
Figura 6.8: Utilizzo CPU di OpenSignal.
6.2.3
Comparazione con Weendy
Weendy è un’applicazione con paradigma di Data Crowd-Sourcing, dove gli
Utenti possono segnalare lo stato delle condizioni climatiche; viene utilizzato
sopratutto dai surfisti che cercano le condizioni ottimali per cavalcare l’onda.
L’utilizzo di CPU di Weendy è molto simile a quello di Fog Escaping e non
sono stati registrati Memory Warning durante l’esecuzione.
6.2 Comparazioni
Figura 6.9: Utilizzo CPU di Weendy.
109
110
6. Validazione
6.3
ScreenShot di Fog Escaping
In questa sezione, sono illustrate le varie fasi di utilizzo dell’applicazione Fog
Escaping, tramite i device iPhone e iPad: Stato iniziale d’avvio, registrazione, login, segnalazione nebbia, ricerca percorso alternativo.
Figura 6.10: Icona di Fog Escaping.
6.3.1
Stato Iniziale
Al primo avvio dell’applicazione, sono disabilitate le funzionalità di segnalazione dello stato ambientale di nebbia e di ricerca di un percorso alternativo.
L’Utente per abilitare le funzionalità dovrà obbligatoriamente utilizzare la
funzionalità di login.
(a) Iphone
(b) Ipad
Figura 6.11: Stato di primo avvio dell’applicazione Fog Escaping
6.3 ScreenShot di Fog Escaping
6.3.2
111
Registrazione
Se i dati inseriti sono corretti, l’Utente viene notificato della corretta registrazione tramite un alert di notifica (Fig. 6.12b). Se i dati inseriti sono
errati, le label relative si colorano di giallo e nella parte bassa della View,
compare l’indicazione di cosa deve essere inserito (Fig. 6.13b).
(a) Inserimento Dati.
(b) Alert di Risposta.
Figura 6.12: Processo di Registrazione.
(a) Utente già presente.
(b) Dati Mancanti.
Figura 6.13: Errore di Registrazione.
112
6.3.3
6. Validazione
Login
La View di Login permette l’inserimento di una e-mail e di una password.
Se i dati inseriti sono corretti, la View viene deallocata e compare un alert
di notifica (Fig. 6.14b). Se i dati inseriti non sono corretti, viene notificato
il problema direttamente nella parte bassa della View (Fig. 6.15b).
(a) Inserimento Dati.
(b) Login Effettuato.
Figura 6.14: Processo di Login.
(a) Errore Dati.
(b) Mancanza Dati.
Figura 6.15: Errore di Login.
6.3 ScreenShot di Fog Escaping
6.3.4
113
Segnalazione Nebbia
Una volta selezionato il valore di visibilità è possibile inviare la segnalazione
di Nebbia premendo il pulsante Invia. La grafica nei dispositivi iPad utilizza
una particolare tipologia di View chiamata Popover (Fig. 6.17a).
(a)
(b)
Figura 6.16: Processo di Segnalazione tramite iPhone.
(a)
(b)
Figura 6.17: Processo di Segnalazione tramite iPad.
114
6.3.5
6. Validazione
Ricerca Percorso Alternativo
In questa View è possibile scegliere una posizione di partenza e arrivo. Al
caricamento viene fatto il geocoding automatico sulla posizione attuale dell’Utente. Alla pressione del pulsante Escape inizia il processo di ricerca del
percorso alternativo che si conclude con la visualizzazione del percorso e delle
icone rappresentanti lo stato delle nebbie.
Figura 6.18: Ricerca Percorso Alternativo su iPhone.
Figura 6.19: Ricerca Percorso Alternativo su iPad.
Conclusioni
Riepilogo
In questa Tesi di laurea, si è affrontato il problema della mobilità veicolare in caso di nebbie. Si è quindi sviluppato un prototipo con architettura
Client-Server, che si è soffermato maggiormente sull’analisi dei dati per la
creazione di un percorso alternativo. Si è preso in considerazione il sistema
operativo mobile di Apple, iOS7 che rappresenta uno dei Sistemi Operativi
mobili maggiormente presenti sul mercato oggigiorno e che possiede un buon
bacino di utenze.
La parte Server è stata sviluppata secondo l’architettura REST; è presente
un Server HTTP che riceve richieste e risponde in modo adeguato ai Client
tramite lo scambio bidirezionale di dati in formato JSON. Nella parte Server
è inclusa la base di dati: un componente molto importante poiché implementa al suo interno, parte della logica di Sistema tramite stored procedure.
La parte Client è un’applicazione per dispositivi iPad e iPhone chiamata Fog Escaping; essa è stata sviluppata secondo il pattern MVC (ModelView-Controller). Fog Escaping implementa un algoritmo Greedy di ricerca
del percorso alternativo, che può essere utilizzato per diverse tipologie di
applicazioni, che descriverò nella sezione sulle estensioni future (6.3.5).
115
116
CONCLUSIONI
Difficoltà emerse
Sono emerse svariate difficoltà al momento della realizzazione.
In primo luogo i servizi di Apple per la gestione delle mappe, possiedono alcuni piccoli “problemi” che è stato necessario arginare; infatti l’oggetto MKDirections, che rappresenta il percorso ottimale generato dai Server Apple,
non è completamente accedibile tramite librerie ad alto livello.
All’inizio dello sviluppo era stata presa in considerazione la libreria di
Google Maps, ma dopo attenta analisi, nessuno dei due sistemi (GoogleMap
e iOS7) permetteva una navigazione attraverso una moltitudine di punti di
soluzione. Si è quindi deciso di utilizzare il sistema più stabile fra i due;
quindi la scelta è ricaduta sulle mappe integrate nel sistema iOS7.
Lo sviluppo della grafica, è iniziato su dispositivo iPad; gli strumenti
messi a disposizione da XCode 5, hanno permesso in tempi brevi, il porting
su iPhone.
La parte più critica del progetto, è stata sicuramente la creazione di un
algoritmo greedy, che permettesse di evitare le nebbie. Prima della decisione finale, ovvero la creazione della Griglia dei Punti di Controllo, sono stati
implementati svariati metodi e algoritmi, che però fallivano sempre in casi
particolari. In seguito è stato necessario correggere alcuni problemi che sono
stati generati dal metodo della Griglia, ma lavorando ininterrottamente, è
stato possibile ottenere un buon risultato, sia in termini grafici sia in termini
computazionali. L’implementazione della parte Server, non ha richiesto particolari sforzi, siccome durante i vari progetti del corso di studi, soprattutto
dell’ultimo anno, erano già state sviluppate le tecnologie PHP e MySQL che
sarebbero state rivisitate per il progetto di Tesi.
Implementazioni Future dell’Algoritmo
L’applicazione Fog Escaping, è nata per cercare un percorso alternativo in
caso di nebbia, ma l’algoritmo per la ricerca di un percorso alternativo, può
essere utilizzato per svariate tipologie di applicazioni.
CONCLUSIONI
117
Ad esempio date le recenti alluvioni nel territorio dell’Emilia-Romagna, si
potrebbe creare un’applicazione, che fa visualizzare un elenco di tutti i ponti
aperti e chiusi nella zona e creare un percorso alternativo che passi per i soli
ponti aperti. Attualmente i cittadini devono rimanere in attesa di queste
informazioni, quando disponibili, direttamente visionando il sito internet di
ogni comune.
Un’altra idea per sfruttare l’algoritmo creato, è quella di utilizzare i dati
ambientali d’inquinamento, per sensibilizzare il cittadino che è intenzionato
a fare una passeggiata o un’attività sportiva, in determinati punti della città.
Questi dati sono raccolti tutti i giorni, e verranno resi disponibili in formato
GeoJSON da ARPA [35]. L’idea è di utilizzare l’algoritmo per consigliare
percorsi che possano, in un qualche modo, far respirare aria migliore.
Estensioni Future
L’applicazione Fog Escaping, è stata sviluppata in modo da poter essere ampliata; in maniera specifica si sono analizzati alcuni contesti di espansione,
che potrebbero essere sviluppati nell’immediato futuro.
Gestione dell’Affidabilità
Innanzitutto è necessario risolvere il problema dell’affidabilità dei dati; questo può essere fatto implementando un sistema simile a quello studiato nel
Capitolo 5, ovvero l’analisi automatica della visibilità, tramite i sensori integrati nel dispositivo. In questo modo si otterrebbero dei valori di nebbia
quantomeno affidabili e dipendenti dai sensori e non da un click sullo schermo. Purtroppo è risaputo che non basta far rilevare il dato ai sensori del
dispositivo; è necessario un sistema di reputazione, che permetta agli altri
utenti di confermare o meno lo stato di nebbia.
118
CONCLUSIONI
Raccolta e Reputazione
Per incoraggiare la raccolta dei dati di nebbia, nel momento in cui una persona porta a termine una segnalazione, sarà richiesto ai cittadini vicini se la
condizione di nebbia è realmente esistente. In cambio della nuova segnalazione l’Utente guadagnerà punti di reputazione. Ovviamente chi segnala in
modo “sbagliato”, verrà punito con una diminuzione della reputazione. Il sistema quindi, dopo aver capito che esiste una condizione di nebbia, richiederà
ad alcuni Utenti che sono man mano più distanti dalla prima segnalazione,
i dati riguardanti la visibilità riscontrata. In questo modo si richiede la partecipazione di un campione di utenti limitrofi, eventualmente interrogando i
client di quelli più affidabili.
Utilizzo dei Nodi Stradali
Per un algoritmo preciso, sarebbe necessario utilizzare una mappatura completa del grafo stradale. Questi dati sono disponibili dalle librerie di OpenStreetMap, richiedendo i nodi che sono all’interno di un quadrato, formato
da due latitudini e due longitudini [36]. In questo modo i Punti di Controllo
sarebbero esattamente parte della strada. In seguito basterebbe inserire i dati ambientali di visibilità e utilizzare l’algoritmo di Dijskra così com’è stato
pensato.
Epilogo
Secondo i sostenitori del movimento Open data, i dati andrebbero trattati
come beni comuni [37].
La cooperazione è la parola “chiave” che permette l’evolversi della comunicazione in modo rapido. Le tecnologie ci aiutano e ci assistono, ma questo
accade solo se queste tecnologie sono programmate per farlo. è inoltre necessario che i dati raccolti siano divulgati; così facendo chiunque potrà fare
la sua parte per risolvere i piccoli e i grandi problemi di ogni giorno.
Bibliografia
[1] Andrew Campbell and Tanzeem Choudhury. From smart to cognitive
phones. IEEE CS, 2012.
[2] Ye Xu, Mu Lin, Hong Lu, Giuseppe Cardone, Nicholas D. Lane, Zhenyu
Chen, Andrew Campbell, and Tanzeem Choudhury. Preference, context
and communities: A multi-faceted approach to predicting smartphone app usage patterns. Dartmouth College, Intel Labs, University of
Bologna, Microsoft Research Asia, Cornell University, 2013.
[3] Andrew T. Campbell, Shane B. Eisenman, Nicholas D. Lane, Emiliano Miluzzo, and Ronald A. Peterson. People-centric urban sensing.
Computer Science, Dartmouth College Computer Science, Electrical
Engineering, Columbia University, 2006.
[4] J. Burke, D. Estring, M. Hansen, A Parker, N. Ramanathan, S. Reddy, and M.B. Srivastava. People-centric urban sensing. Proceedings
of Second Annual International Wirless Internet Conference (WICON),
pages 2–5, August 2006.
[5] R. Rana, C.T. Chou, S. Kanhere, N. Bulusu, and W. Hu. Ear-phone:
An end-to- end participatory urban noise mapping system. Proceedings
of ACM/IEEE IPSN, Stockholm, Sweden, April 2010.
[6] E. Miluzzo, N. Lane, K. Fodor, R. Peterson, S. Eisenman, H. Lu, M. Musolesi, X. Zheng, and A. Campbell. Sensing meets mobile social networks: The design, implementation and evaluation of the cenceme ap119
120
CONCLUSIONI
plication. Proceedings of ACM SenSys, Raleigh, NC, USA, November
2009.
[7] N. Kapadia, A.and Triandopoulos, C. Cornelius, D. Peebles, and D. Kotz.
Anonysense: Opportunistic and privacy-preserving context col-
lection. Indulska, J., Pat- terson, D.J., Rodden, T., Ott, M. (eds.)
PERVASIVE 2008, 2008.
[8] K. Huang, S.S. Kanhere, and W. Hu. Are you contributing trustworthy
data? the case for a reputation framework in participatory sensing.
Proceedings of ACM MSWiM, Bodrum, Turkey, October 2010.
[9] S. Gaonkar, J. Li, and R.R. Choudhury. Micro-blog: Sharing and querying content through mobile phones and social participation. Proceedings
of ACM Mo- biSys, Breckenridge, CO, USA, June 2008.
[10] Robin Kravets, Hilfi Alkaff, Andrew Campbell, Karrie Karahalios, and
Klara Nahrstedt. Crowdwatch: Enabling in-network crowd-sourcing.
University of Illinois and Dartmouth College, 2013.
[11] I. Saleemi, K. Shafique, , and M. Shah.
Probabilistic modeling of
scene dynamics for applications in visual surveillance. Proc. of IEEE
Transactions on Patterns Recognition and Machine Intelligence, 2009.
[12] U. Crowdsourcing. Proceedings of 2nd workshop on ubiquitous crowdsourcing, 2011.
http://www.personal.psu.edu/u1o/crowdsourcing/
program.html., 2011.
[13] S. Bisker and F. Casalegno. Digital volunteerism during disaster: Crowdsourcing information processing.
http://metamanda.com/crowdcomputing/subs/bisker.pdf, 2011.
[14] D. G. Murray, E. Yoneki, J. Crowcroft, and S. Hand. The case for crowd
computing. ACM MobiHeld?10.
CONCLUSIONI
[15] K. Starbird.
121
Digital volunteerism during disaster: Crowdsourcing
information processing. ACM CHI?2011 Workshop, 2011.
[16] S. Reddy, A. Parker, J. Hyman, J. Burke, D. Estin, and M. Hansen.
Image brows- ing, processing and clustering for participatory sensing:
Lessons from a dietsense prototype. Proceedings of the Workshop on
Embedded Networked Sensors (Em- NetS), Cork, Ireland, June 2007.
[17] bewell. http://www.bewellapp.org.
[18] Zhenyu Chen, Mu Lin, Fanglin Chen, Nicholas D. Lane, Giuseppe Cardone, Rui Wang, Tianxing Li, Yiqiang Chen, Tanzeem Choudhury, and
Andrew T. Campbell. Unobtrusive sleep monitoring using smartphones.
Dartmouth College, Chinese Academy of Sciences, Microsoft Research
Asia, Cornell University,University of Bologna, Beijing Key Laboratory
of Mobile Computing and Pervasive Device, 2013.
[19] jawbone up. https://jawbone.com/up.
[20] M. Mun, S. Reddy, and et al. Peir, the personal environmental impact report, as a platform for participatory sensing systems research.
Proceedings of ACM MobiSys, Krakow, Poland, June 2009.
[21] S. Eisenman, E. Miluzzo, N. Lane, R. Peterson, G. Ahn, and A. Campbell. The bikenet mobile sensing system for cyclist experience mapping.
Proceedings of ACM SenSys, Sydney, Australia, November 2007.
[22] Runtastic. https://www.runtastic.com/it.
[23] Runkeeper. http://runkeeper.com/.
[24] Everytrail. http://it.everytrail.com/.
[25] Y. Dong, S.S. Kanhere, C.T. Chou, and N.: Bulusu. Automatic collection of fuel prices from a network of mobile cameras. Proceedings of
IEEE DCOSS 2008, Santorini, Greece, June 2008.
122
CONCLUSIONI
[26] Plugshare. http://www.plugshare.com/.
[27] J. Carrapetta, N. Youdale, A. Chow, and V. Sivaraman. Haze watch
project. http://www.pollution.ee.unsw.edu.au.
[28] Air quality egg community. http://airqualityegg.com/.
[29] Weendy. http://weendy.com/.
[30] P. Mohan, V. Padmanabhan, and R. Ramjee. Nericell: Rich monitoring
of road and traffic conditions using mobile smartphones. Proceedings of
ACM SenSys, Raleigh, NC, USA, November 2008.
[31] Inrix traffic. http://www.inrixtraffic.com/.
[32] Opensignal. http://opensignal.com/.
[33] Waze. https://www.waze.com/it/.
[34] E. W. Dijskra. A note on two problems in connexion with graphs.
Numerishe Mathematik 1, pages 269–271, 1959.
[35] L’acceeso ai dati di arpa emilia-romagna.
http://forges.forumpa.it/assets/Speeches/9932/co_29_cattani.pdf.
[36] Openstreetmap node request.
http://wiki.openstreetmap.org/wiki/API_v0.6.
[37] Open data.
http://it.wikipedia.org/wiki/Dati_aperti#Diritti_fondamentali.
Ringraziamenti
In ordine completamente casuale vorrei ringraziare:
Il Professor Marco Di Felice per l’aiuto nello svolgimento della tesi.
Graziano e Daniela per l’immensa pazienza, consigli e il supporto morale.
Gaia per avermi supportato e per avermi dato la spinta necessaria per ripartire. Iria e Ezio per avermi aiutato nel momento del bisogno. Ermes e Franca
per le cene irripetibili. Enrico e David per tutto il tempo passato assieme.
Richy D. per le tante risate e Eleonora per gli interminabili giri in roller.
Ilaria per la pazienza con David e Alice per la pazienza con Enrico.
Buch per la creatività e le passioni condivise. Alessia per la pazienza e la
capacità di giudizio. Gabri per la dzattera, i flip e il futuro motore a reazione.
Garro per la frase : “Gli amici prima di tutto”. Richy B. per le sue doti di
comunicazione. Nello per la forza d’animo. Chiara per la sua competenza e
il suo aiuto. Casti e Frà per il magnifico accompagnamento. Cesare per aver
addolcito molte giornate amare. Sara per la sua aura di felicità. Corra per
avermi spiegato come funziona l’essere umano. Giorgio per le spiegazioni di
analisi. Biondo e Pier per la compagnia durante gli anni migliori.
Chris per l’appoggio nelle idee e nello studio. Jack che con il suo modo di
fare è capace di farti sorridere sempre. Marika per la sua pazza visione della
vita. Steve per le sue perle e comete. Vale per l’attitudine da killer. Marti
per la Giulietta incorporata. Sonia per la pazienza nel sopportare i compagni.
124
CONCLUSIONI
Luca per la passione nei fagioli. Marco per avermi fatto compagnia in treno
e per i magnifici fumetti. Maggy per il sostegno nei secoli. Silvia per la
sua passione per la natura. Pizzi, Samini, Piwi per gli interminabili discorsi.
Tolsimir, Erundil, Kennerd, Luthien, Astarte, Bolobo, Beyron per i viaggi
meravigliosi. Il Pantegana per i momenti magnifici assieme. L’Alchimista
per il controllo. Pecorè per la perseveranza. Gracca per l’amicizia e la sua
sapienza musicale. War Machine per la preparazione della battaglia contro
il BOSS finale. Griglia, Pinza, Cunsa, Fuoco per il gustosissimo lavoro.
Dasy per i tanti brindisi.
Anna per la forza d’animo e per avermi spronato.
Tutti i professori per le sfide.
Tutte le persone che hanno allietato i viaggi in treno.
Tutti i personaggi che sognando regalano nuove speranze.
Tutti gli altri amici che mi hanno sostenuto in questo percorso.
Scarica

Documento PDF - AMS Tesi di Laurea