E de notorietate că orașul nostru a intrat într-un ritm rapid de dezvoltare. Transportul în comun reflectă și el această evoluție, după cum ne arată tramvaiele noi, stațiile modernizate, bilete prin sms și liniile noi de autobuz. Ne-am gândit că în acest peisaj s-ar potrivi o aplicație interactivă, care reprezintă un pas înainte spre conceptul de "Smart City".
Prima motivație ne-a fost dată încă din anii studenției, când de multe ori să știi care autobuz în ce cartier duce sau când ajunge în stație, era un secret rezervat doar inițiaților; Pe lângă lipsa clarității și a accesibilității informației legate de transportul în comun, o altă motivație a fost dorința de a simplifica prezentarea informației: am încercat să ușurăm folosirea unei hărți schematice.
Știați că, hărțile moderne ale transportului în comun își au originea în eforturile lui Harry Beck din 1931, care a prezentat ideea unei diagrame care conținea doar linii orizontale, verticale și la 45 de grade (3).
Pe majoritatea liniilor am făcut "ture" cu busul, pentru a colecta într-un mod cât mai precis datele GPS ale stațiilor. A fost o experiență interesantă, am văzut condițiile în care se circulă în Cluj- Napoca, am descoperit cartiere și locații despre care nu știam nimic. Dacă vă doriți să descoperiți o altă față a Clujului, vă recomandăm linia 36B care merge spre Bărc, liniile 27 și 28 care duc prin cartierul Gruia sau linia 21 care te plimbă prin Andrei Mureșanu - Bună Ziua.
Pentru construirea hărții am considerat inițial folosirea unor tooluri externe, dar din păcate nu am găsit unul potrivit. Până la urmă am decis să dezvoltăm un tool home-made.
Avantajul constă într-o integrare mai strânsă a hărții cu aplicația: calcularea automată a pozițiilor stațiilor (care e folositoare la interacțiunea utilizatorului cu harta), traducerea automată a hărții în diferite limbi, plasarea diferitelor informații grafice custom, ca de exemplu indicarea râului Someș, marcarea cartierelor, simbolizarea gării.
Construirea hărții a fost similară cu rezolvarea unui puzzle matematic în care mai multe condiții trebuia să fie îndeplinite concomitent: stațiile/traseele comune ale liniilor să fie adiacente, așezate cât mai compact, iar harta să aibă un aspect plăcut, pe cât posibil.
Harta e exportată ca o imagine cu o rezoluție destul de mare, care apoi în pasul al doilea al exportării e prelucrată. Folosirea directă a imaginii originale e ineficientă din punct de vedere a memoriei și a puterii de calcul necesare.
Clasa CATiledLayer din iOS SDK ne sare aici în ajutor. Ea se bazează pe o idee frumoasă de algoritm, despre care cred că merită descrisă. Majoritatea sistemelor de randare a hărților se bazează pe un algoritm similar. Această clasă permite afișarea într-o manieră asincronă a unui layer format din tile-uri. Tile-urile sunt încărcate de la sursă (în cazul nostru suportul de stocare a device-ului) pe un alt thread, fără să afecteze interacțiunea userului cu harta.
Se încarcă doar tile-urile care sunt vizibile pe ecran, ceea ce reduce drastic numărul tile- urilor necesare de încărcat.
Harta e preparată în prealabil și scalată la rezoluții din ce în ce mai mici, fiecare nivel având jumătatea rezoluției nivelului precedent. Fiecare nivel e împărțit în tile-uri de dimensiuni fixe de câte 256x256 pixeli. În timpul prezentării, pe ecran se alege nivelul care e capabil să prezinte tile-uri de mărime între 126- 256 pixeli. Avantajele sunt numeroase: se evită efectul de "pixeling" (similar mipmappingului din grafică), se asigură afișarea pe ecran a unui număr de tile-uri redus și constant (numărul lor depinde de rezoluția ecranului, nu de rezoluția hărții).
Combinat cu un mecanism de caching, această soluție se dovedește a fi una extrem de eficientă.
Harta e localizată în patru limbi: RO, HU, EN, DE. Pentru a minimaliza spațiul celor patru variante de hartă, am implementat refolosirea tile-urilor identice dintre ele.
De ce am ales varianta app și nu web? În primul rând, pentru că avem cunoștințe aprofundate în domeniul aplicațiilor native. În al doilea rând, pentru că aplicația e interactivă, are nevoie de performanță în randare și folosește funcțiile unui device mobil: servicii localizare, giroscop. Și nu în ultimul rând pentru longevitatea codului: folosirea toolsetului nativ și matur creează o siguranță în ceea ce privește continuitatea și calitatea tehnologiei (iOS SDK), evitând astfel situații în care ar trebui să abandonăm o tehnologie din cauza stopării dezvoltării ei.
Pentru a calcula cele mai rapide trasee din punctul A în B, am folosit algoritmul lui Dijkstra, implementat de noi. Având lista de stații și lista liniilor (o linie fiind o succesiune de stații), am construit un graf direcționat, pe care îl trimitem ca input algoritmului. Pentru o călătorie cât mai scurtă, am luat în considerare și cazul în care stațiile sunt atât de apropiate, încât utilizatorul ar putea ajunge pe jos din una în alta. Astfel am introdus și secțiuni de mers pe jos marcate specific.
Din fericire, nu e vorba de coliziuni în trafic, ci de coliziuni virtuale cu scopul aflării următoarei stații spre care se îndreaptă autobuzul. Pentru simplificarea problemei am înscris busul aflat în mișcare într-un cerc cu o rază de 2m și stația într-un cerc cu raza de 100m. Coliziunea dintre două cercuri (dintre care unul se află în mișcare) se poate calcula folosind cunoștințe de bază în matematică/fizică. Problema e asemănătoare cu aflarea punctului de coliziune dintre două bile de biliard. Acest algoritm ne permite să-l anunțăm pe user din timp legat de stația spre care se îndreaptă.
Faptul că majoritatea stațiilor sunt colectate de noi cu o acuratețe mare, permite ca detectarea stației să aibă loc foarte exact.
Un mic detaliu care în pune în dificultate calculele matematice sunt coordonatele GPS se află pe o sferă. Noi am aproximat problema și am transformat coordonatele GPS în coordonate carteziene pe plan 2D, folosind proiecția Mercator (4). Distorsiunea nu e vizibilă pentru utilizator. În acest fel, problema se reduce la aflarea coliziunilor pe o suprafață plană.
Aplicația conține și un feature prin care e afișată o busolă care indică direcția în linie dreaptă către o stație sau POI. Pentru aceasta, trebuie să găsim unghiul dintre direcția nordului și direcția către stație, ambele direcții fiind linii pe o sferă. Dar pentru că pe o sferă nu există linii drepte, am redus și această problemă la una mai simplă în plan, și anume la găsirea unghiului dintre două segmente.
Pentru actualizarea orarului folosim un sistem simplu, având ca suport baza de date realtime Firebase deținută de Google. Baza de date are o structură simplă: o cheie cu o valoare care reprezintă data ultimei actualizări a orarului. Aplicația observă când această valoare e modificată, iar dacă ea diferă de cea pe care o are stocată local, descarcă arhiva orarelor (un fișier zip de 40Kb) și se auto-actualizează. Pentru informarea utilizatorului despre această actualizare am folosit notificări locale iOS. Pentru a asigura și funcționarea offline a aplicației, orarul actualizat e integrat direct în fiecare update nou din AppStore.
La momentul actual, ora sosirii unui autobuz în stație se prezice prin interpolarea orei curente cu ora de pornire, lungimea liniei și viteza autobuzului. Din experiența noastră și a utilizatorilor, rezultatul e destul de exact. Acest sistem nu poate prevedea însă anumite anomalii, ca de exemplu traficul încărcat și ambuteiajele.
Totuși, dacă n-ai apucat să-ți cumperi bilet sau te afli într-o stație fără casă / aparat de bilete, aplicația îți oferă posibilitatea să-ți cumperi bilet prin SMS.
Pentru a asigura un user-experience cât mai fluid, căutarea stațiilor se extinde automat pe toate limbile localizate, pe cartierul care include aceea stație, precum și pe POI-urile din jurul stațiilor. De exemplu, dacă se caută "Házsongárdi", iar device-ul e în limba română, atunci se va găsi ca rezultat denumirea "Cimitirul Central". Similar e și pentru POI-uri, unde căutarea se extinde pe toate limbile și pe numele categoriilor. De exemplu, termenul "Monument" găsește toate POI-urile din categoria "Monumente", nu doar pe cele care au acest text inclus în nume. Acest feature câștigă un sens important într-o aplicație care e dedicată unui oraș multicultural și ușurează astfel găsirea destinațiilor.
Concluzie importantă: e greu să dezvolți o astfel de aplicație, dacă nu ești din oraș. Aici ne diferențiem deliberat de celelalte aplicații generale de transport în comun, care nu au cum să aibă acuratețea informațiilor de la fața locului.
Dincolo de faptul că e o aplicație destinată transportului public din Cluj-Napoca și din împrejurimi, ea se mai poate folosi și ca ghid turistic, conținând atât puncte de interes pentru utilizatori, cât și busola integrată care te conduce către acestea. Considerăm că e o aplicație matură, care doar așteaptă să fie descoperită și folosită de către persoanele potrivite.
Până acum, feedbackul primit din partea utilizatorilor a fost unul pozitiv. Pentru a nu pierde legătura cu utilizatorii, avem opțiuni de contact chiar și în interiorul aplicației și luăm în serios orice idei și semnalări pe care le primim. Am și implementat deja o serie de sugestii primite de la utilizatori. În prezent, jumătate dintre utilizatori sunt străini, iar jumătate provin din țară.
Recomandăm dezvoltatorilor de aplicații mobile o experiență similară, deoarece îi poate ajuta să își formeze o idee completă despre ce înseamnă lansarea unui app: conceperea ideii, implementarea ei, lansarea și mentenanța. Trăim într-o eră în care unui developer îi e mai ușor ca niciodată să lanseze o aplicație proprie.
În plus, un asemenea proiect are pentru noi și un rol de "playground" unde putem testa diferite tehnologii noi, ca de exemplu mai sus menționatul Firebase sau portarea în Swift.
Programarea aplicației a fost realizată de Mátyás Fábián și Sipos István, cu ajutor pe partea PR din partea Raluca Fábián.