Google карты приблизительное расстояние - PullRequest
7 голосов
/ 15 декабря 2011

Я начал создавать веб-сайт, где его пользователи эффективно отслеживаются (они знают, что их отслеживают).Пользователи пройдут по определенному маршруту (вокруг Манчестера, Великобритания, если быть более точным), из которого есть 10 контрольных точек.Контрольная точка - это статическая позиция на карте.Используя API Карт Google, я знаю, что могу нанести на карту положение, то есть контрольную точку.Я также храню время, когда пользователь достигает контрольной точки.Взяв расстояние между контрольными точками, я смог вычислить их среднюю скорость, используя базовую математику.

Теперь то, что я хотел бы сделать, это построить их расчетное положение на основе их скорости.Трудность, с которой я сталкиваюсь, заключается в построении новой позиции x миль / метр (любая единица) из текущей позиции по маршруту .

Если бы это была прямая линия, это было быпросто.

  • Есть ли способ рассчитать расстояние от текущей позиции по маршруту?
  • Существуют ли какие-либо ограничения на количество баллов?
  • Существуют ли конкретные способы сделать это, которых следует избегать?

Чтобы расширить мой примерс изображением:

Example scenario

Представьте, что пользователь достиг маркера первого места в 07:00 и, по оценкам, он достигнет маркера второго места в 09:00.Время (например) сейчас 08:00 утра, что означает, что (по оценкам) пользователь должен находиться примерно на полпути между маркерами.Затем я бы вычислил пройденное ими расстояние (опять же, по оценкам) и наметил их положение на карте «расстояние» от маркера первого места.

Надеюсь, я объяснил сценарий достаточно ясно, чтобы люди могли его понять.

Я относительно новичок в API карт Google, поэтому любые мысли будут полезны.Другие аналогичные вопросы были заданы для SO, но, насколько я вижу, ни на один из них не было получено или не было запрошено столько подробностей, сколько я имею.

Заранее спасибо.

ОБНОВЛЕНИЕ Потратив много времени, пытаясь это решить, я с треском провалился.Вот что я знаю:

  • Я должен создать путь, используя PolyLine (я могу сделать это, у меня есть список lat / lng)
  • Существует расширение JS, называемоеepoly.js, но это не совместимо с V3
  • . Использование spherical.interpolate не сработает, потому что он не следует по пути.

Ответы [ 5 ]

4 голосов
/ 31 января 2012

Я много занимался этим в прошлой жизни как картограф.Ваша полилиния состоит из последовательности точек (широта / долгота).Между каждой последовательной точкой вы вычисляете расстояние, складывая его по мере продвижения, пока не достигнете желаемого расстояния.

Реальный трюк - это вычисление расстояния между двумя точками широты и долготы, которые являются сферическими координатами (то есть точками).на изогнутой поверхности).Поскольку вы имеете дело с довольно небольшими расстояниями, вы можете преобразовать координаты широты / долготы в локальную сеточную систему карты (которая является плоской).Расстояние между двумя точками будет тогда прямым прямым углом Пифагора (сумма квадратов и все такое).На веб-сайте Movable Type есть много хороших (javascript) -кодов на этом здесь .

Вторым способом будет вычисление сферического расстояния - не красиво, но вы можете видеть это здесь

Лично я бы пошел по пути преобразования координат в локальную сеточную систему, которая в Великобритании должна быть OSGB.Это наименее искаженный метод.

Надеюсь, это поможет

Редактировать: Я предположил, что вы можете извлечь координаты полилинии с помощью API Google.Я не сделал этого в версии 3 API, но это должно быть прямо вперед.Кроме того, координаты полилинии должны быть достаточно близко друг к другу, чтобы вам не нужно было интерполировать промежуточные точки - просто возьмите ближайшую координату полилинии (избавит вас от необходимости выполнять расчет направления и расстояния).

Edit2- С кодом

Я попытался собрать код, но, вероятно, не успею закончить его в течение вашего срока (у меня есть работа).Вы должны быть в состоянии получить Jist.Код преобразования координат взят из веб-сайта с подвижным типом, а базовый материал карт Google - из одного из примеров Google.По сути, он рисует полилинию с помощью щелчков мыши, помещает широту / долготу каждого щелчка мышью в поле таблицы, преобразует координаты в OSGB, а затем в сетку OS (см. здесь ).После первого щелчка он рассчитывает расстояние между каждой последующей точкой.Надеюсь, что это поможет вам.

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
      html { height: 100% }
      body { height: 100%; margin: 0; padding: 0 }
      #map_canvas { height: 100% }
    </style>
    <script type="text/javascript"
      src="http://maps.googleapis.com/maps/api/js?sensor=false">
    </script>

      <script src="Map.js" type="text/javascript"></script>
  </head>
  <body onload="initialize()" style="width:100%;height:100%">
  <div style="margin-right:auto;margin-left:auto;margin-top:100px;width:900px;">
    <div id="map_canvas" style="width:600px; height:500px;float:left;"></div>
      <div style="float:right;">
  <table>
  <tr>
    <td align="right">Latitude:</td>
    <td><input id="txtLatitude" maxlength="11" type="text" class="inputField"/></td>
  </tr>
  <tr>
    <td align="right">Longitude:</td>
    <td><input id="txtLongitude" maxlength="11" type="text" class="inputField"/></td>
  </tr>

  <tr>
    <td align="right">Eastings:</td>
    <td><input id="txtEast" maxlength="11" type="text" class="inputField"/></td>
  </tr>
  <tr>
    <td align="right">Northings:</td>
    <td><input id="txtNorth" maxlength="11" type="text" class="inputField"/></td>
  </tr>

   <tr>
    <td align="right">Distance:</td>
    <td><input id="txtDistance" maxlength="11" type="text" class="inputField"/></td>
  </tr>

  <tr>
    <td colspan=2 align="right">

    </td>
  </tr>
</table>
</div>
  </div>



  </body>
</html>

Map.js:

function initialize() {

    var myOptions = {
        center: new google.maps.LatLng(53.43057, -2.14727),
        zoom: 18,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    var tempIcon = new google.maps.MarkerImage(
    "http://labs.google.com/ridefinder/images/mm_20_green.png",
    new google.maps.Size(12, 20),
    new google.maps.Size(6, 20)
    );
    var newShadow = new google.maps.MarkerImage(
    "http://labs.google.com/ridefinder/images/mm_20_shadow.png",
    new google.maps.Size(22, 20),
    new google.maps.Point(13, 13)
    );

    var tempMarker = new google.maps.Marker();
    tempMarker.setOptions({
        icon: tempIcon,
        shadow: newShadow,
        draggable: true
    });
    var latlngs = new google.maps.MVCArray();
    var displayPath = new google.maps.Polyline({
        map: map,
        strokeColor: "#FF0000",
        strokeOpacity: 1.0,
        strokeWeight: 2,
        path: latlngs
    });
    var lastEast;
    var lastNorth;
    function showTempMarker(e) {
        //Pythagorean distance calculates the length of the  hypotenuse (the sloping side)
        //of a right angle triangle. Plain (cartesian) coordinates are all right angle triangles.
        //The length of the hypotenuse is always the distance between two coordinates.
        //One side of the triangle is the difference in east coordinate and the other is
        //the difference in north coordinates
        function pythagorasDistance(E, N) {
            if (lastEast) {
                if (lastEast) {
                    //difference in east coordinates. We don't know what direction we are going so
                    //it could be a negative number - so just take the absolute value (ie - get rid of any minus sign)
                    var EastDistance = Math.abs(E - lastEast);
                    //difference in north coordinates
                    var NorthDistance = Math.abs(N - lastNorth);
                    //take the power
                    var EastPower = Math.pow(EastDistance, 2);
                    var NorthPower = Math.pow(NorthDistance, 2);
                    //add them together and take the square root
                    var pythagorasDistance = Math.sqrt(EastPower + NorthPower );
                    //round the answer to get rid of ridiculous decimal places (we're not measuring to the neares millimetre)
                    var result = Math.floor(pythagorasDistance);

                    document.getElementById('txtDistance').value = result;
                }
            }

        }

        function calcCatesian(degLat, degLng) {
            var OSGBLL = LL.convertWGS84toOSGB36(new LatLon(degLat, degLng));
            var EN = LL.LatLongToOSGrid(OSGBLL);

            document.getElementById('txtEast').value = EN.east;
            document.getElementById('txtNorth').value = EN.north;
            pythagorasDistance(EN.east, EN.north);
            lastEast = EN.east;
            lastNorth = EN.north;

        }

        tempMarker.setPosition(e.latLng);
        var lat = e.latLng.lat();
        var lng = e.latLng.lng();
        document.getElementById('txtLatitude').value = lat;
        document.getElementById('txtLongitude').value = lng;
        calcCatesian(lat, lng);

        google.maps.event.addListener(tempMarker, "drag", function() {
            document.getElementById('txtLatitude').value = tempMarker.getPosition().lat();
            document.getElementById('txtLongitude').value = tempMarker.getPosition().lng();
            calcCatesian(lat, lng);
        });
        tempMarker.setMap(map);

        var newLocation = new google.maps.LatLng(lat, lng);
        latlngs.push(newLocation);
        displayPath.setPath(latlngs);

    }

    google.maps.event.addListener(map, "click", showTempMarker);
}

// ---- the following are duplicated from LatLong.html ---- //

/*
 * construct a LatLon object: arguments in numeric degrees & metres
 *
 * note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)
 */
function LatLon(lat, lon, height) {
    if (arguments.length < 3)
        height = 0;
    this.lat = lat;
    this.lon = lon;
    this.height = height;
}

function setPrototypes() {

    /*
     * represent point {lat, lon} in standard representation
     */
    LatLon.prototype.toString = function() {
        return this.lat.toLat() + ', ' + this.lon.toLon();
    }
    // extend String object with method for parsing degrees or lat/long values to numeric degrees
    //
    // this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by
    // compass direction (NSEW). A variety of separators are accepted (eg 3º 37' 09"W) or fixed-width
    // format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation
    // is done).

    String.prototype.parseDeg = function() {
        if (!isNaN(this))
            return Number(this);                 // signed decimal degrees without NSEW

        var degLL = this.replace(/^-/, '').replace(/[NSEW]/i, '');  // strip off any sign or compass dir'n
        var dms = degLL.split(/[^0-9.]+/);                     // split out separate d/m/s
        for (var i in dms)
            if (dms[i] == '')
                dms.splice(i, 1);
        // remove empty elements (see note below)
        switch (dms.length) {                                  // convert to decimal degrees...
            case 3:
                // interpret 3-part result as d/m/s
                var deg = dms[0] / 1 + dms[1] / 60 + dms[2] / 3600;
                break;
            case 2:
                // interpret 2-part result as d/m
                var deg = dms[0] / 1 + dms[1] / 60;
                break;
            case 1:
                // decimal or non-separated dddmmss
                if (/[NS]/i.test(this))
                    degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
                var deg = dms[0].slice(0, 3) / 1 + dms[0].slice(3, 5) / 60 + dms[0].slice(5) / 3600;
                break;
            default:
                return NaN;
        }
        if (/^-/.test(this) || /[WS]/i.test(this))
            deg = -deg; // take '-', west and south as -ve
        return deg;
    }
    // note: whitespace at start/end will split() into empty elements (except in IE)

    // extend Number object with methods for converting degrees/radians

    Number.prototype.toRad = function() {  // convert degrees to radians
        return this * Math.PI / 180;
    }
    Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
        return this * 180 / Math.PI;
    }
    // extend Number object with methods for presenting bearings & lat/longs

    Number.prototype.toDMS = function(dp) {  // convert numeric degrees to deg/min/sec
        if (arguments.length < 1)
            dp = 0;      // if no decimal places argument, round to int seconds
        var d = Math.abs(this);  // (unsigned result ready for appending compass dir'n)
        var deg = Math.floor(d);
        var min = Math.floor((d - deg) * 60);
        var sec = ((d - deg - min / 60) * 3600).toFixed(dp);
        // fix any nonsensical rounding-up
        if (sec == 60) {
            sec = (0).toFixed(dp);
            min++;
        }
        if (min == 60) {
            min = 0;
            deg++;
        }
        if (deg == 360)
            deg = 0;
        // add leading zeros if required
        if (deg < 100)
            deg = '0' + deg;
        if (deg < 10)
            deg = '0' + deg;
        if (min < 10)
            min = '0' + min;
        if (sec < 10)
            sec = '0' + sec;
        return deg + '\u00B0' + min + '\u2032' + sec + '\u2033';
    }
    Number.prototype.toLat = function(dp) {  // convert numeric degrees to deg/min/sec latitude
        return this.toDMS(dp).slice(1) + (this < 0 ? 'S' : 'N');  // knock off initial '0' for lat!
    }
    Number.prototype.toLon = function(dp) {  // convert numeric degrees to deg/min/sec longitude
        return this.toDMS(dp) + (this > 0 ? 'E' : 'W');
    }
    /*
     * extend Number object with methods for converting degrees/radians
     */
    Number.prototype.toRad = function() {  // convert degrees to radians
        return this * Math.PI / 180;
    }
    Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
        return this * 180 / Math.PI;
    }
    /*
     * pad a number with sufficient leading zeros to make it w chars wide
     */
    Number.prototype.padLZ = function(w) {
        var n = this.toString();
        for (var i = 0; i < w - n.length; i++)
            n = '0' + n;
        return n;
    }
};

setPrototypes();

LL = function() {

    // ellipse parameters
    var e = {
        WGS84: {
            a: 6378137,
            b: 6356752.3142,
            f: 1 / 298.257223563
        },
        Airy1830: {
            a: 6377563.396,
            b: 6356256.910,
            f: 1 / 299.3249646
        }
    };

    // helmert transform parameters
    var h = {
        WGS84toOSGB36: {
            tx: -446.448,
            ty: 125.157,
            tz: -542.060,   // m
            rx: -0.1502,
            ry: -0.2470,
            rz: -0.8421,  // sec
            s: 20.4894
        },                               // ppm
        OSGB36toWGS84: {
            tx: 446.448,
            ty: -125.157,
            tz: 542.060,
            rx: 0.1502,
            ry: 0.2470,
            rz: 0.8421,
            s: -20.4894
        }
    };

    return {

        convertOSGB36toWGS84: function(p1) {
            var p2 = this.convert(p1, e.Airy1830, h.OSGB36toWGS84, e.WGS84);
            return p2;
        },
        convertWGS84toOSGB36: function(p1) {
            var p2 = this.convert(p1, e.WGS84, h.WGS84toOSGB36, e.Airy1830);
            return p2;
        },
        convert: function(p1, e1, t, e2) {
            // -- convert polar to cartesian coordinates (using ellipse 1)

            p1.lat = p1.lat.toRad();
            p1.lon = p1.lon.toRad();

            var a = e1.a, b = e1.b;

            var sinPhi = Math.sin(p1.lat), cosPhi = Math.cos(p1.lat);
            var sinLambda = Math.sin(p1.lon), cosLambda = Math.cos(p1.lon);
            var H = p1.height;

            var eSq = (a * a - b * b) / (a * a);
            var nu = a / Math.sqrt(1 - eSq * sinPhi * sinPhi);

            var x1 = (nu + H) * cosPhi * cosLambda;
            var y1 = (nu + H) * cosPhi * sinLambda;
            var z1 = ((1 - eSq) * nu + H) * sinPhi;

            // -- apply helmert transform using appropriate params

            var tx = t.tx, ty = t.ty, tz = t.tz;
            var rx = t.rx / 3600 * Math.PI / 180;  // normalise seconds to radians
            var ry = t.ry / 3600 * Math.PI / 180;
            var rz = t.rz / 3600 * Math.PI / 180;
            var s1 = t.s / 1e6 + 1;              // normalise ppm to (s+1)

            // apply transform
            var x2 = tx + x1 * s1 - y1 * rz + z1 * ry;
            var y2 = ty + x1 * rz + y1 * s1 - z1 * rx;
            var z2 = tz - x1 * ry + y1 * rx + z1 * s1;

            // -- convert cartesian to polar coordinates (using ellipse 2)

            a = e2.a, b = e2.b;
            var precision = 4 / a;  // results accurate to around 4 metres

            eSq = (a * a - b * b) / (a * a);
            var p = Math.sqrt(x2 * x2 + y2 * y2);
            var phi = Math.atan2(z2, p * (1 - eSq)), phiP = 2 * Math.PI;
            while (Math.abs(phi - phiP) > precision) {
                nu = a / Math.sqrt(1 - eSq * Math.sin(phi) * Math.sin(phi));
                phiP = phi;
                phi = Math.atan2(z2 + eSq * nu * Math.sin(phi), p);
            }
            var lambda = Math.atan2(y2, x2);
            H = p / Math.cos(phi) - nu;

            return new LatLon(phi.toDeg(), lambda.toDeg(), H);
        },
        /*
        * convert numeric grid reference (in metres) to standard-form grid ref
        */
        gridrefNumToLet: function(e, n, digits) {
            // get the 100km-grid indices
            var e100k = Math.floor(e / 100000), n100k = Math.floor(n / 100000);

            if (e100k < 0 || e100k > 6 || n100k < 0 || n100k > 12)
                return '';

            // translate those into numeric equivalents of the grid letters
            var l1 = (19 - n100k) - (19 - n100k) % 5 + Math.floor((e100k + 10) / 5);
            var l2 = (19 - n100k) * 5 % 25 + e100k % 5;

            // compensate for skipped 'I' and build grid letter-pairs
            if (l1 > 7)
                l1++;
            if (l2 > 7)
                l2++;
            var letPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));

            // strip 100km-grid indices from easting & northing, and reduce precision
            e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
            n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));

            var gridRef = letPair + e.padLZ(digits / 2) + n.padLZ(digits / 2);

            return gridRef;
        },
        LatLongToOSGrid: function(p) {
            var lat = p.lat.toRad(), lon = p.lon.toRad();

            var a = 6377563.396, b = 6356256.910;          // Airy 1830 major & minor semi-axes
            var F0 = 0.9996012717;                         // NatGrid scale factor on central meridian
            var lat0 = (49).toRad(), lon0 = (-2).toRad();  // NatGrid true origin
            var N0 = -100000, E0 = 400000;                 // northing & easting of true origin, metres
            var e2 = 1 - (b * b) / (a * a);                      // eccentricity squared
            var n = (a - b) / (a + b), n2 = n * n, n3 = n * n * n;

            var cosLat = Math.cos(lat), sinLat = Math.sin(lat);
            var nu = a * F0 / Math.sqrt(1 - e2 * sinLat * sinLat);              // transverse radius of curvature
            var rho = a * F0 * (1 - e2) / Math.pow(1 - e2 * sinLat * sinLat, 1.5);  // meridional radius of curvature
            var eta2 = nu / rho - 1;

            var Ma = (1 + n + (5 / 4) * n2 + (5 / 4) * n3) * (lat - lat0);
            var Mb = (3 * n + 3 * n * n + (21 / 8) * n3) * Math.sin(lat - lat0) * Math.cos(lat + lat0);
            var Mc = ((15 / 8) * n2 + (15 / 8) * n3) * Math.sin(2 * (lat - lat0)) * Math.cos(2 * (lat + lat0));
            var Md = (35 / 24) * n3 * Math.sin(3 * (lat - lat0)) * Math.cos(3 * (lat + lat0));
            var M = b * F0 * (Ma - Mb + Mc - Md);              // meridional arc

            var cos3lat = cosLat * cosLat * cosLat;
            var cos5lat = cos3lat * cosLat * cosLat;
            var tan2lat = Math.tan(lat) * Math.tan(lat);
            var tan4lat = tan2lat * tan2lat;

            var I = M + N0;
            var II = (nu / 2) * sinLat * cosLat;
            var III = (nu / 24) * sinLat * cos3lat * (5 - tan2lat + 9 * eta2);
            var IIIA = (nu / 720) * sinLat * cos5lat * (61 - 58 * tan2lat + tan4lat);
            var IV = nu * cosLat;
            var V = (nu / 6) * cos3lat * (nu / rho - tan2lat);
            var VI = (nu / 120) * cos5lat * (5 - 18 * tan2lat + tan4lat + 14 * eta2 - 58 * tan2lat * eta2);

            var dLon = lon - lon0;
            var dLon2 = dLon * dLon, dLon3 = dLon2 * dLon, dLon4 = dLon3 * dLon, dLon5 = dLon4 * dLon, dLon6 = dLon5 * dLon;

            var N = I + II * dLon2 + III * dLon4 + IIIA * dLon6;
            var E = E0 + IV * dLon + V * dLon3 + VI * dLon5;

            E = Math.floor(E * 100) / 100;
            N = Math.floor(N * 100) / 100;

            //return this.gridrefNumToLet(E, N, 8);
            return { east: E, north: N }
        ;
        }
    }

} ();
2 голосов
/ 01 февраля 2012

Я думаю, что вы в значительной степени уже получили ответ, за исключением одной маленькой детали, о которой я не видел, чтобы кто-то прямо упоминал: вам нужно использовать закодированный polyline из steps, чтобы добраться до точки, где вы будетеинтерполируйте между двумя точками, которые достаточно близки, так что прямая линия между ними является хорошим приближением к форме маршрута.

Давайте рассмотрим пример:

Направления движения из Мадрида в Толедо:

http://maps.googleapis.com/maps/api/directions/json?origin=Toledo&destination=Madrid&region=es&sensor=false

Срединная точка (на полпути через весь маршрут) будет где-то в самой большой step длиной почти 50 км:

{
   "distance" : {
      "text" : "49.7 km",
      "value" : 49697
   },
   "duration" : {
      "text" : "26 mins",
      "value" : 1570
   },
   "end_location" : {
      "lat" : 40.26681000000001,
      "lng" : -3.888580
   },
   "html_instructions" : "Continue onto \u003cb\u003eAP-41\u003c/b\u003e\u003cdiv style=\"font-size:0.9em\"\u003eToll road\u003c/div\u003e",
   "polyline" : {
      "points" : "kdtrFj`~VEkA[oLEy@Cs@KeAM_BOgBy@eGs@iFWgBS{AQ{AQcBMuAM}BKcBGiCM_EGaFKgEKeDOqC[yFWwCIi@Is@i@_EaAsFy@aEeAcEsAqEuAeE]w@k@qAeAcCm@sA}@cBgB{CaBgCiEyFuB}BsBuBaDwCa@]_CsBmD_Di@g@aAaAs@s@{@aAU[q@w@s@{@wE{Ge@s@_@o@a@q@o@kAmAaCaAqBeAcCw@kBy@yBw@_Cg@aB}AkEoBgFyDwIcBwDa@iAcBwCgAcBsAiBy@uAeCiDqBeCaB_BuA_BiDeC{@o@u@k@cD{B}@g@y@_@k@]cD_BkD{AwBu@cA]eAYsD_AuE_AqBY{Du@_BW_AQm@K_AOiAWuAa@qA_@mA_@aBi@MGOGMGy@[OI_Bw@uBkAkDsBaAg@oEiCg@YeEcC}As@m@WqCmAmEeBuAe@mDeAqCq@qCm@iB]eBY}BYeCYi@C{@IgBMwCMmAEmAC{A@mB?wBFsBBiBHeAJcBNgBNcBRcC\\qCd@sBb@eAXeBd@uBn@{Bp@uAd@}B~@gD|AmCrA{@j@}Az@kDvB{AbAqA|@}AnAaAx@aAv@}AtAaA`AwClD{HzImH~IiF|F{@~@o@v@qAhAsAhAqA`AyAbA{A~@m@Xw@h@gCnAiBz@uAt@wAh@}@XwCz@qBd@qCf@gBXkBTw@FaCTmDPsADwDJgCFoFXwDXoDb@gCd@wB`@gCh@_D~@qC~@gC~@wChAmDxAaC|@sCbAgEzAuGbBaB`@cFdAo@NoAXiC^cD^oDXmEToBJkABA?Q@_@@yDBwBAoB?wBEm@A_CKO?_EUcD[eEe@uAQq@I]GqDs@e@Ii@K_@IOEgAWk@MsBi@mBg@WIc@MkEwA{Am@yB}@yDcB_CgAsAs@eB}@aBaAiD{ByCqBkA}@mA}@uAiAwCcCyAoAmEiE{@aAgAyA{@cAmAuAaBsBkAyAgBcCwAoBwAwByCyEyBmD{BsDgCaEuA{Co@eAuC_Fs@iA{@iAo@_A{A}BkGmHmAwAeBaBcBeBcHsGmCkCyCyCm@m@m@m@_A_AkDaDkCiCkDgD}@y@iE_FcC}CkBkCw@gAs@cAcC{D_BmCe@}@}AuCsAkCiCqFkAgCe@kAgAeCw@mBuAaDWg@g@iAEE{AqCq@kA_@k@oCwDuAeBoAqAUQ_@YMOm@k@e@g@_@]u@m@k@a@i@_@YOSOe@[k@_@w@c@a@Ok@WyAo@y@[eBm@}Ac@{Bk@kASwBS}AMyBO}BGuGJsAJmCRuDn@iCn@}C`AwBx@kB|@{BfAmBfAkCdBaCzA_BpA_BlAuAnAeCdCuD`EgBzBgClDyBrD{AtCy@bB_@b@Wl@c@`AWr@KVSd@MXIPGPSd@MZQb@MZ_@bAm@dBQd@[`A_@jAGRIVGPGVIVSt@k@xBe@jBKd@U`As@nDKb@Q`AgAtHADM~ACNK|@SpBQhBKnBKxACv@OhDO~EGdFAhA@|CC~B?rA@vB@hB@dD@vBAbCCvCEzBGpBEpAEpAKrBI~@Ej@Et@WxCa@vDYrBq@bEQfAUnAy@vD}BtJUx@K^wBfGwCdHqBxD_B`CsBbDwCnEgCrCuCzCyBpBiCzBmBvAaC|AuAv@eAj@OHuAp@}@^oBz@eExAgBb@uFpAaC`@mDb@iCRmADaDFy@B}E?aEQaJcAuB]uA[uBc@kDu@eD{@{Cs@iDu@wBe@eEo@{BQwDYiEMkBEaA?aA?aB?_B@aBDsBJwDT{Ed@o@JcALi@JcBVuBb@sA\\eAV{Ct@aA\\cBh@_Bh@mAb@sCpAwDhB_CpA}BvAg@\\mAr@aBjAqBzAgBxAeBzAoBlB_C~BgAhAUV[`@uCjD_BvBQVGDw@fAiAdBeAdBuC`Fe@|@wCbGU^]r@]r@oAvCeApCQZKXo@vBu@|B}@zCoAjEg@vBc@~AOt@k@~Bu@jD}@tDc@zAW`AWv@Ux@[bAw@xBuAhD{@jByCvFcClDwBvCkCrCgCdCsBzAgBnAkBjAkBbAmAj@gAf@mDjAsBl@sBf@uBb@oBXaBLiBNaADgABuABkBCgEUuCU}Ck@_Cg@kCu@yB{@{BaAqBaA}@i@kAq@OIe@[g@_@a@WmAaAeAy@iAeA}@_AmAsAu@w@{@gA_@e@o@cAk@_Ay@sAYm@_@m@_@u@]q@u@cBi@eA[y@Se@g@iAYs@_@oAMi@[aAa@uA_@wAS}@a@cB]wAWqAI]CKgAyDu@yCo@eCgAmDu@cCmAoDmBwEgAaCa@_AcByCqDwGiBkCw@iAgBaCkAoAiC{CkBiBuAsAoBcBeEaD}BaBs@c@gCyAKEoBgAuAk@eBy@oAe@uCcAgBo@mD_AkCk@kAUsASgAQeAIm@ImCW_E[_FWwCSkBMuAM[E{@IGAmBUmCc@}@QcAUsA_@cAWgBi@w@UwAk@a@MmAi@eAe@yBiAk@[SMKEw@g@k@_@w@e@aC_Bc@]yBgBeCmB}BmB}BsB_BoAw@o@s@g@oDiCuA{@_BcAgAq@uBsAaAc@{@_@y@_@sAm@yD}AeDgAsDiAeCeAaCy@iCgAiBcAeAc@c@OyE{A{Ag@y@YaBm@{Aq@gAm@i@][YMMYWaGwGi@y@{A{B_A{Aw@iAs@iA_A}AcAaBsAiBeBkBoAiAaBsA{AcAoAq@iB}@qBu@wBk@cBa@qAW}@I}CSwEBiDVcBR_BXiCr@gBp@wBbAkAp@qA|@y@l@wCjC{@~@gArAmCzDiAnBm@tAu@jBq@pBmAvDwAnFw@bCELq@tBw@pBgAdCS\\qCnF_@f@yBtC{AhBqAvAkBhB{ArAyAhAg@Ze@Z{BrAiBz@SHy@^OFs@X_AZ_Bd@WJaDr@}B\\eBPoBNq@F_@@iC@gACu@Ai@Ey@IQC_B[}Bo@_@Ks@S"
   },
   "start_location" : {
      "lat" : 39.92150,
      "lng" : -3.927260
   },
   "travel_mode" : "DRIVING"
},

Боюсь, эта полилиния слишком длинная (2856 символов), чтобы отображать ее непосредственно в API статических карт , но это не обязательно, просто было бы хорошим способом показать полилинию прямо здесь,В любом случае, вы можете использовать Interactive Polyline Encoder Utility , чтобы вставить эту кодированную полилинию (после замены \\ на \), чтобы увидеть ее.

Теперь давайте представим, что вам нужно найтиточка на этом маршруте, которая составляет ровно 20 км.с самого начала этого шага.То есть точка между start_location и end_location, которая находится на расстоянии 20 000 метров от start_location по маршруту, определенному вышеуказанной ломаной линией.

В вашем приложении вы будете использовать кодировку Методы в библиотеке геометрии (которые вам нужно явно загрузить ) для декодирования этой ломаной линии во весь массив точек LatLng.Затем вы должны использовать computeDistanceBetween между каждыми двумя смежными точками, чтобы выяснить, какая из них является первой точкой LatLng (Y) на этой ломаной линии, которая больше 20 000 от start_location.Затем вы берете эту точку плюс предыдущую (X) и выполняете прямую интерполяцию между X и Y.На этом этапе вы можете рассчитывать на прямую линию между этими двумя точками, чтобы получить разумное приближение к форме маршрута.

Имейте в виду, это довольно подробный расчет, который может оказаться слишком дорогим.Если вы столкнулись с проблемами производительности из-за большого размера полилинии, вы можете упростить ее, отбросив часть точек.Умное выполнение этого упрощения может быть, опять же, дорогостоящим, поэтому я бы оставил его простым;)

2 голосов
/ 27 января 2012

Я думаю, что вы ищете что-то похожее на эту функцию, которая возвращает точку с определенным процентом по заданной линии.К сожалению, я не знаю ничего о порте javascript этой функции, но, вероятно, стоит посмотреть.

Между тем вот краткая концепция взлома, которая может дать вам достаточно деталей для ваших нужд:

  • Начните с вашей ломаной линии (для простоты, давайте предположим, что у вас есть только один путь,который представляет собой серию LatLngs)
  • Когда вы хотите оценить, где находится человек, возьмите его процент вдоль пути, как определено временем (например, в 8 утра они 50% вдоль)
  • Теперь для каждого LatLng в вашем пути вычислите его дробное расстояние вдоль общей длины пути, добавив расстояния между LatLngs (вы можете использовать computeLength для пути и computeDistanceBetween для каждого LatLng)
  • Как тольковы получаете на долю> 50% (в данном случае), вы знаете, что человек находится между этим LatLng и предыдущим.Затем вы можете точно рассчитать, как далеко, а затем точно расположить точку, если вы хотите, или просто пропустите этот шаг, если это довольно короткий отрезок, и поместите их маркер на один из этих LatLng.
  • Выше приведеноОбщая концепция, но, конечно, вы должны оптимизировать, предварительно рассчитав процентное расстояние для каждого LatLng только один раз для каждого Пути и сохранив его в отдельном объекте, и следите за своим последним индексом в пути, чтобы вы не начинали с начала следующеговремя, когда вы рассчитываете их расстояние и т. д.

Надеюсь, это поможет.

1 голос
/ 01 февраля 2012

Этот сайт: http://www.gmap -pedometer.com / может представлять интерес, поскольку он позволяет пользователю рисовать маршруты и добавляет маркеры в милях или километрах вдоль маршрута, поэтому он должен выполнять аналогичные действия.расчет на тот, который вам нужен.

1 голос
/ 16 декабря 2011

Я бы сказал, что это выполнимо.:-) Вот как я это визуализирую, но я не проверял ничего из этого.

Сначала определите PolyLine, основываясь на «угаданном маршруте», по которому должны идти пользователи.Сохраните это в локальной переменной в вашем js.Будет удобно иметь много точек, чтобы улучшить оценку.

Затем установите интервал (window.setInterval), чтобы проверять наличие обновлений в позициях пользователей, скажем, каждые 30 секунд.Если позиция новее интервала - отобразите известную позицию и нарисуйте сплошную линию из последней известной позиции, создав линию известных данных.(setPath)

Если новых данных нет, выполните простой расчет скорости, используя последние несколько известных точек.

Используя скорость и таймфрейм, рассчитайте приблизительное расстояние.

Используя рассчитанное расстояние, загружайте ваш предполагаемый объект маршрута и «ходите» пункт за пунктом в «предполагаемом маршруте», пока псевдо пройденное расстояние не станет почти равным вашей оценке.Затем верните точку, где вы достигли правильного расстояния.

Нарисуйте пунктирную линию от последнего известного местоположения к предполагаемому.

Удачи!


PS.

A PolyLine - это линейный объект, состоящий из множества путей и путевых точек

Расчет длин между точками с использованием сферической геометрии функция пространств имен "computeLength"

...