Flying memes

Isocrono e Google Map API

Un isocrono non è nient’altro che una curva che unisce su di una mappai punti che distano uno stesso intervallo temporale (a piedi, o con un mezzo di trasporto) da un punto dato. In questo articolo, che funge da approfondimento della homepage del progetto, vorrei entrare un pò nel merito del piccolo script da utilizzare per calcolare un’approssimazione di isocrono usando le API di Google Maps.

Lo script si compone di tre parti, una (classica) funzione di inizializzazione,  una funzione che effettua il GeoCoding della località della quale si vuole calcolare l’isocrono e la funzione chiave, che cicla su ognuno dei raggi (il numero di raggi è impostabile, di default 10) della circonferenza costruita intorno a tale località e per ogni raggio si muove verso l’esterno misurando la distanza in minuti dal centro, quando trova un punto che sorpassa il tempo limite dato lo script mette un marker.

Lo script passa al raggio successivo quando rileva una misurazione che supera del 50% il tempo limite dato.


    function crawlpoint(px,py,mins){
        var point      = new GPoint(px,py);
        var destpoint  = new GPoint(px + x,py + y);   

        directions.loadFromWaypoints(new Array(point.y + "," + point.x ,destpoint.y + "," + destpoint.x),{preserveViewport:true});
        x = x + (inc_x * Math.sin(start_s));
        y = y + (inc_y * Math.cos(start_s));
        m = m + 1;

        if (directions.getNumRoutes() > 0){
            document.getElementById('txt1').value = 'y' + document.getElementById('txt1').value
            var curr_meas = directions.getDuration().seconds/60;
            if (prev_meas <= mins && curr_meas > mins ){
                map.addOverlay(new GMarker(prev_dest,{title:'Distance: ' + directions.getDuration().html}));
                found     = 1;
            }else{
                prev_dest = destpoint;
                prev_meas = curr_meas;
            }

            if(curr_meas > (mins + (mins * 0.4)) || (m > 20 && found ==1) || m > 50){
                points.push(new GLatLng(prev_dest.y, prev_dest.x));
                start_s = start_s + slice;
                x = inc_x;
                y = inc_y;
                m = 0;
                found = 0;
                prev_meas = 0;
                curr_meas = 0;
                prev_dest = point;
                directions.clear();

                if(start_s >= (2*Math.PI)){
                    start_s = 0;
                    $('#loader').hide();
                    clearInterval(intval);
                }
            }

        }else{
            document.getElementById('txt1').value = 'n' + document.getElementById('txt1').value
        }
    }

Possiamo spezzare la funzione in tre punti distinti, la prima parte invoca le Directions API, per calcolare la distanza tra il centro e un punto (destpoint) posizionato sul raggio attivo (il cui angolo è memorizzato in start_s, inizialmente a 0) ad una distanza espressa da due variabili x e y. Una volta calcolato il percorso x e y vengono incrementate in modo che al prossimo giro puntino ad un punto sullo stesso raggio un poco più avanti.

La seconda parte aggiunge un marker se tra la durata del percorso attuale supera per la prima volta il limite di tempo inserito.

La terza parte resetta tutti i contatori e avanza al raggio successivo se la misurazione temporale corrente eccede del 50% il tempo limite inserito o se sono state effettuate più di venti misurazioni con l’identificazione di un marker o più di 50 misurazioni.

Trovate il codice nella sua interezza sul mio account di github, potete inoltre testare il tutto su di una pagina di demo.

PS: credo che l’algoritmo sia altamente perfezionabile, ad esempio introducendo alcuni concetti di reinforcement learning per la ricerca degli zeri della funzione T(R(p1,p2)) – t dove T(R(p1,p2)) è il tempo di percorrenza del percorso tra p1 e p2 e t è il tempo limite dell’isocrono.

Tags: , ,