Autore Topic: GroundOverlay o TileOverlay?  (Letto 500 volte)

Offline Elmvor

  • Utente normale
  • ***
  • Post: 166
  • Respect: 0
    • Mostra profilo
  • Sistema operativo:
    Ubuntu 14.04, Windows 8.1
GroundOverlay o TileOverlay?
« il: 08 Luglio 2014, 10:58:47 CEST »
0
Salve. Ogni tanto riprendo la mia vecchia app per cercare di completarla/migliorarla e mi trovo di fronte ad un nuovo problema. Questo in particolare mi sembra piuttosto complicato. Il discorso è che se aggiungo alla GoogleMap tante polylines essa rallenta fino a diventare praticamente inutilizzabile. Documentandomi un po ho capito che per ovviare a questo problema devo creare un'immagine del tracciato (e non aggiungere le polilinee direttamente alla GoogleMap) ed attaccarla alla GoogleMap, ovviamente nella posizione corretta. Per fare questo bisogna utilizzare un TileOverlay o un GroundOverlay. Detto questo, ci sono varie cose che non capisco:

1) Quale devo utilizzare dei due? Il secondo mi sembra di più semplice gestione del primo.
2) Devo imparare a creare un'immagine del tracciato che sia perfettamente compatibile con la GoogleMap. E' un bel lavoro di plotting, e mi servirebbe qualche consiglio a riguardo.
3) Ogni volta che si disegna un nuovo percorso viene di fatto creata una nuova immagine no? Devo evitare che queste immagini vadano ad intasare la memoria del dispositivo.

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:GroundOverlay o TileOverlay?
« Risposta #1 il: 08 Luglio 2014, 11:31:06 CEST »
0
Beh la domanda che fai non è di cosi semplice risposta, per molti motivi:
Dici che hai una serie di polilinee che rallentano il rendering, ma queste polilinee sono "dinamiche" o "statiche", sono sempre le stesse o cambiano?
Dalla tua domanda, cambia tantissimo la risposta.
Se sono statiche, puoi farti il rendering "offline" delle stesse e creare un groundoverlay (che altro non è che una immagine piazzata sulla mappa).
vedi l'esempio:
https://developers.google.com/maps/documentation/android/groundoverlay

Un TileOverlay invece è una cosa piu complessa, e viene usata per "renderizzare" delle mappe in overlay "al volo":
https://developers.google.com/maps/documentation/android/tileoverlay
Esempi di questo possono essere le mappe di OpenStreetMap, Bing (è fuori dai termini di servizio ma funzionano) e anche delle tue custom map.
Tutto ciò che devi fare è implementare il corretto URLTileProvider, il quale dirà a google maps come fare la richiesta al server per ottenere le tile (immagini) per una determinata zona e livello di zoom.
Questo implica che tu metta i dati online su un server di mappa (esiste Geoserver come open e free), e li esponga con la proiezione di google maps (900913, leggasi google). Occhio che per il mondo intero il sistema 900913 (che ha come alias 3857) è in METRI, mentre google maps per sue strane ragioni usa LatLng (latitudine e longitudine). Se usi il sistema 4326 (che è normalmente in LatLng) non hai grossi problemi, solo immagini stretchate se sono larghe dall'equatore a uno dei poli.
Tutti questo si applica se il tracciato e una polilinea preesistente sul server, altrimenti è dura farti dare dal server una polilinea creata al volo (non impossibile ma neanche banale).

Per curiosità, quante poly disegni? Con quanti punti l'una?
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Elmvor

  • Utente normale
  • ***
  • Post: 166
  • Respect: 0
    • Mostra profilo
  • Sistema operativo:
    Ubuntu 14.04, Windows 8.1
Re:GroundOverlay o TileOverlay?
« Risposta #2 il: 08 Luglio 2014, 11:49:37 CEST »
0
Miii che casino. Il numero di polilinee dipende dal percorso. Quel che fa la mia app è disegnare il percorso che passa attraverso i vari markers inseriti dall'utente. Faccio delle richieste HTTP ed ottengo il JSON per ottenere le polilinee. Una volta disegnato il percorso è statico. Cambia se l'utente muove o rimuove i markers e avvia nuovamente il calcolo. A quel punto il precedente percorso viene cancellato e viene disegnato quello nuovo. Ho notato una cosa. Un percorso disegnato attraverso due soli markers (partenza ed arrivo) rallenta molto meno rispetto allo stesso identico percorso disegnato però attraverso più markers intermedi.

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:GroundOverlay o TileOverlay?
« Risposta #3 il: 08 Luglio 2014, 12:17:19 CEST »
0
Miii che casino. Il numero di polilinee dipende dal percorso. Quel che fa la mia app è disegnare il percorso che passa attraverso i vari markers inseriti dall'utente. Faccio delle richieste HTTP ed ottengo il JSON per ottenere le polilinee. Una volta disegnato il percorso è statico. Cambia se l'utente muove o rimuove i markers e avvia nuovamente il calcolo. A quel punto il precedente percorso viene cancellato e viene disegnato quello nuovo. Ho notato una cosa. Un percorso disegnato attraverso due soli markers (partenza ed arrivo) rallenta molto meno rispetto allo stesso identico percorso disegnato però attraverso più markers intermedi.
Bene, allora in questo caso d'uso non puoi farci niente (ti toccherebbe fare un server di mezzo che calcola il percorso e crea i GroundOverlay, troppo complesso.
Il tuo problema mi sa che è dovuto alle troppe polylinee mostrate. Io ho polylinee anche di migliaia di punti, ma sono polylinee uniche (una polylinea con 1000 punti è più leggera di 999 polilinee a coppie di punti).
Perchè se tu crei una polylinea per ogni coppia di marker, ne hai N-1, mentre se fai una polylinea unica ne hai 1 di N punti, molto piu leggera.
Ovviamente ci perdi in flessibilità (dimensione e spessore linea non personalizzabile per ogni tratto), ma vabbe...

Prova a farti dare il percorso e a unire tutte le polylinee in una unica (è un addAll sulla lista dei points)
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Elmvor

  • Utente normale
  • ***
  • Post: 166
  • Respect: 0
    • Mostra profilo
  • Sistema operativo:
    Ubuntu 14.04, Windows 8.1
Re:GroundOverlay o TileOverlay?
« Risposta #4 il: 08 Luglio 2014, 12:45:51 CEST »
0
Scusami, non credo di aver capito come creare un'unica polilinea.

Questo è il codice che prende le coppie di LatLng dai markers inseriti ed esegue un AsyncTask per ogni coppia:

Codice: [Seleziona]
for(int i = 0; i < markers.size() - 1; i++) {
            Marker firstMarker = markers.get(i);
            Marker secondMarker = markers.get(i + 1);
            //I extract latitude and longitude from the markers
            LatLng firstLatLng = new LatLng(firstMarker.getPosition().latitude, firstMarker.getPosition().longitude);
            LatLng secondLatLng = new LatLng(secondMarker.getPosition().latitude, secondMarker.getPosition().longitude);

            //Ogni volta si costruisce un URL aggiornato per la nuova coppia di markers
            String URL = Utilities.getInstance().makeURL(firstLatLng.latitude, firstLatLng.longitude,
                    secondLatLng.latitude, secondLatLng.longitude, travelMode);

            AbstractAsyncTask asyncTask = new TrackMarkersAsyncTask(context, googleMap, URL, connectionTimeout,
                    dataTimeout, coordinates, polylines, length, duration);
            asyncTask.execute();
        }

L'AsyncTask esegue il disegno effettivo:

Codice: [Seleziona]
for(int i = 0; i < coordinates.size() - 1; i++) {
            LatLng start = coordinates.get(i);
            LatLng end = coordinates.get(i + 1);
            Polyline polyline = googleMap.addPolyline(new PolylineOptions().add(start, end).
                    width(3).color(Color.GREEN).geodesic(true));
            polylines.add(polyline);
        }

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:GroundOverlay o TileOverlay?
« Risposta #5 il: 08 Luglio 2014, 14:44:24 CEST »
+1
Scusami, non credo di aver capito come creare un'unica polilinea.

Questo è il codice che prende le coppie di LatLng dai markers inseriti ed esegue un AsyncTask per ogni coppia:

Codice: [Seleziona]
for(int i = 0; i < markers.size() - 1; i++) {
            Marker firstMarker = markers.get(i);
            Marker secondMarker = markers.get(i + 1);
            //I extract latitude and longitude from the markers
            LatLng firstLatLng = new LatLng(firstMarker.getPosition().latitude, firstMarker.getPosition().longitude);
            LatLng secondLatLng = new LatLng(secondMarker.getPosition().latitude, secondMarker.getPosition().longitude);

            //Ogni volta si costruisce un URL aggiornato per la nuova coppia di markers
            String URL = Utilities.getInstance().makeURL(firstLatLng.latitude, firstLatLng.longitude,
                    secondLatLng.latitude, secondLatLng.longitude, travelMode);

            AbstractAsyncTask asyncTask = new TrackMarkersAsyncTask(context, googleMap, URL, connectionTimeout,
                    dataTimeout, coordinates, polylines, length, duration);
            asyncTask.execute();
        }

L'AsyncTask esegue il disegno effettivo:

Codice: [Seleziona]
for(int i = 0; i < coordinates.size() - 1; i++) {
            LatLng start = coordinates.get(i);
            LatLng end = coordinates.get(i + 1);
            Polyline polyline = googleMap.addPolyline(new PolylineOptions().add(start, end).
                    width(3).color(Color.GREEN).geodesic(true));
            polylines.add(polyline);
        }

mmm fatto cosi non è proprio ottimizzato eh...
non avvii un async task ma ne avvii esattamente markers.size() - 1
Ti convene fare un ciclo che ti genera TUTTI gli URL, visto che, se vai sulla documentazione ufficiale di AsyncTask, l'esempio base è un download di N file, quindi puoi semplificare e alleggerire la cosa...
Codice (Java): [Seleziona]
 protected Long doInBackground(URL... urls) fai la stessa cosa, invece che un Long restituisci una List<LatLng> points, che poi disegnerai tutti in un colpo.

PS: Occhio che il tuo metodo di disegno è ancora peggio di come previsto all'inizio, perchè tu disegni una polilinea per ogni coppia di coordinate di OGNI tratto calcolato, quindi hai milioni di polilinee! Un vero disastro!
Il fix piu veloce che puoi fare è sul disegno nell'asynctask:
Codice: [Seleziona]
            Polyline polyline = googleMap.addPolyline(new PolylineOptions().addAll(coordinates).
                    width(3).color(Color.GREEN).geodesic(true));
            polylines.add(polyline);       
Dando per scontato che coordinates sia una List<LatLng> ovviamente....
facendo cosi dovresti disegnare già molte meno polilinee (al massimo markers.size()-1).
Se dopo fai anche il fix prima del PS ottimizzi ancora di piu la cosa.
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline Elmvor

  • Utente normale
  • ***
  • Post: 166
  • Respect: 0
    • Mostra profilo
  • Sistema operativo:
    Ubuntu 14.04, Windows 8.1
Re:GroundOverlay o TileOverlay?
« Risposta #6 il: 08 Luglio 2014, 15:31:58 CEST »
0
Guarda, mi sono reso conto del primo problema mentre ti rispondevo. Mi stavo giusto chiedendo perché diamine creo un AsyncTask ad ogni ciclo, è la cosa più inefficiente del mondo. Per il secondo problema beh... non ci ero arrivato, ti ringrazio tantissimo :O

Provo ad implementare le modifiche.

Update: funziona tutto alla perfezione e molto meglio di prima, ti sono veramente grato!  :D
« Ultima modifica: 08 Luglio 2014, 22:52:05 CEST da Elmvor »