2011-12-14 23 views
7

Zacząłem tworzyć stronę internetową, na której użytkownicy są skutecznie śledzeni (wiedzą, że są śledzeni). Użytkownicy będą poruszać się po określonej trasie (dokładniej w okolicach Manchesteru, Wielka Brytania), z której jest 10 punktów kontrolnych. Punkt kontrolny to statyczna pozycja na mapie. Korzystanie z Google Maps API Wiem, że mogę wykreślić pozycję na mapie, np. Punkt kontrolny. Przechowuję także czas, w którym użytkownik osiąga wspomniany punkt kontrolny. Biorąc odległość między punktami kontrolnymi, jestem w stanie obliczyć ich średnią prędkość za pomocą podstawowej matematyki.Google maps odległość approximation

Teraz chciałbym wykreślić ich szacunkową pozycję na podstawie ich prędkości. Trudność, którą mam, polega na wykreślaniu nowej pozycji x mil/metrów (dowolna jednostka) z bieżącej pozycji wzdłuż trasy.

Gdyby to była linia prosta, byłoby to proste.

  • Czy istnieje sposób obliczenia odległości od aktualnej pozycji na trasie?
  • Czy są jakieś ograniczenia dotyczące liczby punktów?
  • Czy istnieją konkretne sposoby robienia tego, czego należy unikać?

Aby rozwinąć mój przykład z obrazka:

Example scenario

Wyobraźmy sobie, że użytkownik osiągnął pierwsze miejsce znacznik na 07:00, a szacuje się, że dotrą one na drugim miejscu znacznik na 09 : 00am. Obecnie czas (na przykład) wynosi 08:00, co oznacza, że ​​(szacowany) użytkownik powinien znajdować się w połowie odległości między znacznikami. Następnie obliczyłbym odległość, którą przeszli (ponownie, oszacowano) i wykreślili swoją pozycję na mapie "odległość" od znacznika pierwszego miejsca.

Mam nadzieję, że wyjaśniłem scenariusz wystarczająco jasny, aby ludzie mogli zrozumieć.

Jestem stosunkowo nowy w Google Maps API, więc wszelkie przemyślenia byłyby pomocne. Inne podobne pytania zostały zadane w SO, ale z tego, co widzę, nikt nie otrzymał odpowiedzi lub poprosił o tak wiele szczegółów jak ja.

Z góry dziękuję.

AKTUALIZACJA: Spędziwszy dużo czasu, próbując to rozwiązać, nie udało mi się. Oto, co wiem:

  • należy utworzyć ścieżkę za pomocą polilinii (można to zrobić, mam listę lat/LNG)
  • Jest JS rozszerzeń o nazwie epoly.js ale to ISN Kompatybilny z V3
  • Użycie narzędzia sferycznego nie będzie działało, ponieważ nie podąża ścieżką.
+0

Czy używana trasa (niebieska linia) to PolyLine? Jak to jest zdefiniowane? –

+0

Ze względu na ten obrazek po prostu kliknąłem mapę i dodałem znaczniki miejsc. Nie sprawdzałem, jak to zrobić za pomocą interfejsu API. Zakładam, że może to być po prostu PolyLine (cokolwiek to jest). Chciałem sprawdzić, czy koncepcja była wykonalna, zanim poświęciłem jej dużo czasu. –

+0

Inna opcja - wystarczy przenieść plik epoly.js do wersji v3. Nie wygląda to tak trudno, po prostu trzeba opracować odpowiednie funkcje podstawowe - nie trzeba rozumieć faktycznych obliczeń matematycznych. Może nawet po prostu wyrwać kod z funkcji GetPointAtDistance - nie trzeba przenosić całej biblioteki. – barryhunter

Odpowiedz

4

Zrobiłem wiele z tych rzeczy w poprzednim życiu jako kartograf. Twoja polilinia składa się z kolejnych punktów (współrzędne długie/długie). Pomiędzy każdym kolejnym punktem obliczyć odległość, dodając go w miarę postępów, aż dojdziesz do pożądanej odległości.

Prawdziwa sztuczka polega na obliczeniu odległości między dwoma punktami długości/długości, które są współrzędnymi sferycznymi (tj. Punktami na zakrzywionej powierzchni). Ponieważ masz do czynienia z dość małymi odległościami, możesz z łatwością przekonwertować współrzędne lat/long na lokalny system siatki mapy (który jest płaski). Odległość między dwoma punktami to prosty pythagoras z kątem prostym (suma kwadratów i tyle). Strona Movable Type ma wiele dobrego (javascript) kodu na tym here.

Drugim sposobem byłoby zrobić kulisty obliczanie długości - nie całkiem ale widać to here

Osobiście poszedłbym drogę przekształcania współrzędnych do lokalnej sieci energetycznej, która w Wielkiej Brytanii powinny być OSGB. Jest to najmniej wykrzywiona metoda.

Nadzieja to pomaga

Edit: mam przyjąć, że można wyodrębnić swoją łamaną współrzędne za pomocą interfejsu API Google. Nie zrobiłem tego w wersji 3 api, ale powinno to być proste. Ponadto współrzędne polilinii powinny być dość blisko siebie, aby nie trzeba było interpolować punktów pośrednich - wystarczy chwycić najbliższą współrzędną polilinii (oszczędza się konieczność wykonania obliczenia namiaru i odległości).

Edit2 - Z kodeksu

miałem iść na wprowadzenie kodu razem, ale prawdopodobnie nie będzie miał czasu, aby zakończyć ją w swoim terminie (ja mam pracy). Powinieneś być w stanie uzyskać jist. Kod konwersji współrzędnych jest usuwany z witryny internetowej typu ruchomego i podstawowe mapy google z jednego z przykładów Google'a. Zasadniczo rysuje polilinię za pomocą kliknięć myszką, umieszcza długość/szerokość każdego kliknięcia myszą w polu tabeli, zamienia współrzędne na OSGB, a następnie na siatkę OS (patrz here). Po pierwszym kliknięciu oblicza odległość między kolejnymi punktami. Mam nadzieję, że to Ci pomoże w drodze.

<!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 } 
     ; 
     } 
    } 

}(); 
1

Powiedziałbym, że jest to wykonalne. :-) Tak to wizualizuję, ale nie testowałem żadnego z nich.

Najpierw należy zdefiniować PolyLine w oparciu o "odgadniętą trasę", którą użytkownicy powinni podjąć. Zapisz to w zmiennej lokalnej w twoim js. Przydaje się wiele punktów, aby lepiej oszacować punkt.

Następnie ustaw interwał (window.setInterval), aby sprawdzić aktualizacje w pozycjach użytkowników, powiedzmy co 30 sekund. Jeśli pozycja jest nowsza od przedziału - wyświetl znaną pozycję i narysuj ciągłą linię od ostatniej znanej pozycji, tworząc linię znanych danych. (setPath)

Gdy nie ma nowych danych, wykonaj proste obliczenia prędkości, korzystając z kilku najnowszych znanych punktów.

Przy użyciu prędkości i ram czasowych oblicz szacunkową odległość do przebycia.

Korzystając z obliczonej odległości, załaduj szacowany obiekt trasy i "chodź" punkt po punkcie w "odgadywanej trasie", aż odległość pseudo-marszu będzie prawie równa szacunkowej wartości. Następnie zwróć punkt, w którym osiągnąłeś właściwą odległość.

Narysuj kropkowaną linię od ostatniej znanej lokalizacji do zgadywanej.

Powodzenia!


PS.

PolyLine jest obiektem linia składająca się z wielu ścieżek i waypointów

Oblicz długości między punktami korzystających geometry spherical Przestrzenie nazw funkcji „computeLength”

2

Myślę, że szukasz czegoś podobnego do this funkcji, która zwraca wskaż pewien procent wzdłuż danej linii. Unfortuntaely Nie jestem świadomy od portu javascript tej funkcji, ale prawdopodobnie warto spojrzeć.

Tymczasem oto szybkie koncepcja hack, które mogą dać wystarczająco dużo szczegółów do swoich potrzeb:

  • Start z łamaną (dla uproszczenia załóżmy, że mamy tylko jedną ścieżkę, która to seria LatLngs)
  • Gdy chcesz oszacować, gdzie jest dana osoba, weź ich procent wzdłuż ścieżki, zgodnie z czasem (na przykład 8 rano są one o 50% wzdłuż)
  • Teraz dla każdego LatLng na swojej drodze, oblicz to ułamkowe odległość wzdłuż całkowitej długości ścieżki, dodając odległości między latLngs (możesz użyć com puteLength dla ścieżki i computeDistanceBetween dla każdej LatLng) Gdy tylko dojdziesz do ułamka> 50% wzdłuż (w tym przypadku), wiesz, że ta osoba jest pomiędzy tą LatLng a poprzednią. Następnie możesz obliczyć dokładnie, jak daleko i jak dokładnie umieścić punkt, jeśli chcesz, lub po prostu pominąć ten krok, jeśli jest to dość krótki segment i umieścić swój znacznik na jednym z tych latLngs.
  • Powyższa koncepcja jest ogólna, ale oczywiście należy ją zoptymalizować, wstępnie obliczając procentowe odległości dla każdej LatLng tylko raz dla każdej Ścieżki i zachowując ją w osobnym obiekcie, i śledzić ostatni indeks na ścieżce, tak abyś zacznij od początku następnym razem, gdy obliczysz ich odległość, itp.

Mam nadzieję, że to pomoże.

1

Ta witryna: http://www.gmap-pedometer.com/ mogą być interesujące, gdyż pozwala trasy remis użytkownika i dodaje mila lub km znaczniki na trasie, więc należy robić podobne obliczenia do tego, którego potrzebujesz.

2

myślę, że dość dużo już dostałem odpowiedź, z wyjątkiem jednego małego szczegółu, że nie widziałem nikogo wspomnieć wyraźnie: trzeba użyć zakodowanego polyline z steps aby dostać się do punktu, w którym będzie interpolację między dwa punkty, które są wystarczająco blisko, aby linia prosta między nimi była dobrym przybliżeniem do kształtu trasy.

Zobaczmy przykład:

dojechać z Madrytu do Toledo:

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

punkt środkowy (półmetku całej trasy) byłoby gdzieś w największym step który jest prawie 50 km długości:

{ 
    "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[[email protected]@[email protected]@iFWgBS{AQ{AQcBMuAM}BKcBGiCM_EGaFKgEKeDOqC[[email protected]@[email protected][email protected]][email protected]@[email protected]}@cBgB{CaBgCiEyFuB}[email protected]][email protected]@[email protected]@{@aAU[[email protected]@[email protected]{@wE{[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]}[email protected]@uAeCiDqBeCaB_BuA_BiDeC{@[email protected]@[email protected]{B}@[email protected]@[email protected]@]cD_BkD{[email protected]]eAYsD_AuE_AqBY{[email protected][email protected][email protected][email protected][email protected]@[email protected][[email protected]@[email protected]}[email protected]@[email protected]@[email protected]]eBY}[email protected]{@IgBMwCMmAEmAC{[email protected]?wBFsBBiBHeAJcBNgBNcBRcC\\[email protected]@[email protected]@{[email protected]@}[email protected]|AmCrA{@[email protected]}[email protected]{AbAqA|@}[email protected]@}AtAaA`AwClD{HzImH~IiF|F{@[email protected]@[email protected]`AyAbA{[email protected]@[email protected]@[email protected]@[email protected]}@[email protected]@[email protected]@[email protected]@wB`@[email protected][email protected][email protected][email protected]|@sCbAgEzAuGbBaB`@[email protected]^cD^[email protected][email protected]@[email protected]_CKO?_EUcD[[email protected]@I][email protected]@[email protected][email protected]@[email protected]@[email protected]{[email protected]}@[email protected]}@aBaAiD{ByCqBkA}@mA}@uAiAwCcCyAoAmEiE{@aAgAyA{@cAmAuAaBsBkAyAgBcCwAoBwAwByCyEyBmD{BsDgCaEuA{[email protected][email protected]{@[email protected]_A{A}[email protected]@[email protected]@_A_AkDaDkCiCkDgD}@[email protected]_FcC}[email protected]@cAcC{[email protected]}@}[email protected]@[email protected]@iAEE{[email protected][email protected]@[email protected]@[email protected]@[email protected][email protected]][email protected]@[email protected]@[email protected][email protected]@[[email protected][email protected]@[email protected]@[email protected]@[email protected][[email protected]}[email protected]{[email protected]}AMyBO}[email protected]@}C`[email protected]|@{BfAmBfAkCdBaCzA_BpA_BlAuAnAeCdCuD`EgBzBgClDyBrD{[email protected][email protected]@[email protected]@`[email protected]@[email protected]@[email protected]@[email protected][`[email protected]@[email protected]@[email protected]`[email protected]@Q`AgAtHADM~ACNK|@[email protected][email protected]|[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@vD}[email protected]^wBfGwCdHqBxD_B`CsBbDwCnEgCrCuCzCyBpBiCzBmBvAaC|[email protected]@[email protected]}@^[email protected]@uFpAaC`@[email protected]@B}E?aEQaJcAuB]uA[[email protected]@eD{@{[email protected]@[email protected]@{[email protected]{[email protected]@[email protected]@sA\\eAV{[email protected]\\[email protected][email protected]@sCpAwDhB_CpA}[email protected]\\[email protected]_C~BgAhAUV[`@[email protected]`[email protected]|@wCbGU^][email protected]][email protected]@[email protected]|B}@[email protected]@[email protected]@[email protected]}@[email protected]`[email protected]@[[email protected]{@[email protected]@[email protected]@[email protected]}[email protected][email protected]@yB{@{BaAqBaA}@[email protected]@[email protected][[email protected][email protected]@[email protected]}@[email protected]@{@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@][email protected]@[email protected][[email protected]@[email protected]@[email protected]@[[email protected][email protected]}@[email protected]]wAWqAI][email protected]@[email protected]@[email protected]{CkBiBuAsAoBcBeEaD}[email protected]@[email protected]@[email protected]@[email protected]@ImCW_E[_FWwCSkBMuAM[E{@[email protected]}@[email protected]@[email protected]@[email protected]@[email protected]@[[email protected]@[email protected][email protected]@[email protected][email protected]]yBgBeCmB}BmB}[email protected]@[email protected]@oDiCuA{@[email protected]@{@[email protected]@[email protected]@yD}[email protected]@[email protected]{A{[email protected]@[email protected]{[email protected]@[email protected]][[email protected]@{A{B_A{[email protected]@iA_A}AcAaBsAiBeBkBoAiAaBsA{[email protected]}@[email protected]@[email protected]}@I}[email protected]@[email protected]|@[email protected]@wCjC{@[email protected]@[email protected]@[email protected]@[email protected]\\[email protected]@yBtC{AhBqAvAkBhB{[email protected]@Z{[email protected]@^[email protected][email protected]@}B\\[email protected][email protected]@[email protected]@[email protected]@IQC_B[}[email protected][email protected]@S" 
    }, 
    "start_location" : { 
     "lat" : 39.92150, 
     "lng" : -3.927260 
    }, 
    "travel_mode" : "DRIVING" 
}, 

Obawiam się, że ta polilinia jest zbyt długa (2856 znaków) do display it directly in the Static Maps API, ale to nie jest konieczne, to po prostu dobry sposób, żeby pokazać polilinię właśnie tutaj. W każdym razie możesz użyć Interactive Polyline Encoder Utility, aby wkleić tę zakodowaną polilinię (po zastąpieniu \\ przez \), aby ją zobaczyć.

Teraz wyobraźmy sobie, że musisz znaleźć punkt na tej trasie, która wynosi dokładnie 20 km. od początku tego etapu. To jest punkt między start_location i end_location, czyli 20 000 metrów od start_location, wzdłuż trasy wyznaczonej przez powyższą polilinię.

W swojej aplikacji użyjesz Encoding Methods w Bibliotece Geometrii (którą musisz load explicitly), aby zdekodować tę polilinię w całej tablicy punktów LatLng. Następnie użyjesz computeDistanceBetween pomiędzy dwoma sąsiednimi punktami, aby ustalić, który z nich jest pierwszym punktem latania (Y) w tej polilinie, która jest większa niż 20 000 od start_location. Następnie weź ten punkt plus poprzedni (X) i wykonaj liniową interpolację między X i Y. W tym momencie możesz liczyć na linię prostą między tymi dwoma punktami, aby być rozsądnym przybliżeniem do kształtu trasy.

Pamiętaj, że jest to dość szczegółowe obliczenie, które może okazać się zbyt drogie. Jeśli trafisz na problemy z wydajnością ze względu na duży rozmiar polilinii, możesz go uprościć, upuszczając część punktów. Uproszczone robienie tego może być znowu drogie, więc powinienem zachować prostotę;)

Powiązane problemy