2011-12-14 12 views
7

私は、ユーザーが効果的に追跡されている(彼らが追跡されていることを知っている)ウェブサイトを作成し始めました。ユーザーは10のチェックポイントがある特定のルート(より正確にはマンチェスター、英国のまわり)を歩くでしょう。チェックポイントはマップ上の静的な位置です。 Google Maps APIを使用すると、マップ上の位置、つまりチェックポイントをプロットすることができます。私は、ユーザーが前記チェックポイントに到達する時刻も記憶している。チェックポイント間の距離をとって、私は基本的な数学を使って平均速度を計算することができます。Google maps距離近似

私がしたいのは、スピードに基づいて推定位置をプロットすることです。現在の位置からルートに沿ってxマイル/メートル(任意の単位)の新しい位置をプロットしています。

直線であれば、これは簡単だったでしょう。

  • ルートに沿った現在位置からの距離を計算する方法はありますか?
  • ポイント数に制限はありますか?
  • これを回避する具体的な方法はありませんか?画像で私の例を拡大して

Example scenario

ユーザーが07:00で最初の場所のマーカーに達し、彼らが09で2位のマーカーに達するだろうと推定だと想像して:00am。今の時間は(例えば)08:00です。これは、ユーザーがマーカー間の半分の距離にある(推定された)ことを意味します。次に、彼らが歩いた距離(やはり推定)を計算し、最初の場所のマーカーから離れたマップの「距離」上の位置をプロットします。

私は人々が理解するのに十分なシナリオを説明してくれることを願っています。

私はGoogleマップAPIに比較的新しいので、どのような考えも参考になります。他にも同様の質問がありましたが、私が見ることができるものから、答えが得られていない、

ありがとうございます。

更新日:私はそれを試してみるのに多くの時間を費やしてしまって、私は悲惨に失敗しました。ここで私が知っている:

  • 私はポリラインを使用してパスを作成する必要があります(私はこれを行うことができ、私は緯度/経度のリストを持っている)
  • epoly.jsと呼ばれるJSの拡張機能が、このISNがありますV3と互換性がありません
  • 球形補間を使用すると、パスをたどらないため作業ができません。
+0

使用しているルート(青い線)はPolyLineですか。それとも、この単純化をスマートに行うと高価になるかもしれません。どのように定義されていますか? –

+0

その画像のために、私は地図をクリックして場所マーカーを追加するだけでした。私はAPIを使ってそれを行う方法を調べていません。私はそれがちょうどPolyLine(それが何であれ)であると仮定します。私はそのコンセプトがそれに多くの時間を費やす前に実現可能かどうかを見たいと思っていました。 –

+0

他のオプション - 単にepoly.jsをv3に移植します。それは難しく見えません。実際の数学を理解する必要はありません。 GetPointAtDistance関数からコードを取り出すこともできます - ライブラリ全体を移植する必要はありません。 – barryhunter

答えて

4

私は、以前の人生で地図作成者として多くのことをしていました。ポリラインは一連のポイント(緯度/経度座標)で構成されています。連続する各点の間に距離を計算し、目的の距離に達するまで移動します。

実際のトリックは、球面座標(すなわち、曲面上の点)である2つの緯度/経度の間の距離を計算することです。かなり小さい距離を扱っているので、緯度/経度座標をローカルのマップグリッドシステム(フラット)に変換することができます。 2点間の距離は、直進直角ピタゴラス(四角形とそのすべての合計)です。 Movable Typeのウェブサイトには、hereにたくさんの良い(javascript)コードがあります。

第二の方法は、球状の距離計算を行うことであろう - きれいではありませんが、あなたはそれがhere

個人的に私は英国にあるべきローカルグリッドシステムに座標を変換するルートを行くと思い見ることができますOSGB。その最も歪曲された方法です。

希望はこのことができます

編集:私はあなたのポリラインは、GoogleのAPIを使用して座標を抽出することを想定してきました 。私はAPIのバージョン3でこれをやっていないが、それはまっすぐでなければならない。また、ポリラインの座標はかなり近似している必要があります。中間点を補間する必要はありません。最も近いポリライン座標を取得するだけです(ベアリングと距離計算が不要になります)。

EDIT2 - コード

と私は一緒にいくつかのコードを置くことで、外出先に持っていた、おそらく(私は仕事を持っている)あなたの制限時間内に終了する時間がありません。あなたはジストを得ることができるはずです。座標変換コードは可動型ウェブサイトから持ち上げられ、基本的なGoogleマップはgoogleの例の1つからものをマップします。基本的にマウスクリックでポリラインを描き、各マウスクリックの緯度/経度をテーブルフィールドに置き、座標をOSGBに変換してからOSグリッドに変換します(here参照)。最初のクリックの後、各後続点間の距離が計算されます。これがあなたを道に導くことを願っています。

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

私はそれが可能だと思います。 :-)これは私がそれを可視化する方法ですが、私はそれをテストしていません。

まず、ユーザーが想定する「推測されたルート」に基づいてPolyLineを定義します。それをあなたのjsのローカル変数に格納します。見積もりポイントをより良くするために、多くのポイントを持つことは便利です。

次に、間隔(window.setInterval)を設定して、ユーザーの位置、たとえば30秒ごとに更新を確認します。位置が間隔よりも新しい場合は、既知の位置を表示し、最後の既知の位置から実線を描き、既知のデータの線を作成します。 (setPath)

新しいデータが存在しない場合は、最新のいくつかの既知の点を使用して簡単な速度計算を行います。

速度と時間枠を使用して、推定移動距離を計算します。

計算された距離を使用して、擬似歩行距離が見積もりにほぼ等しくなるまで、推定ルートオブジェクトをロードし、「推測されたルート」のポイントごとに「ウォーク」します。その後、正しい距離に達したポイントを返します。

最後の既知の場所から推測された場所まで点線を描きます。

幸運を祈る!


PS。

PolyLineは多くのパスとウェイポイント

からなるラインオブジェクトである

計算はgeometry spherical名前空間に返す関数「computeLength」

2

私はあなたがthis機能に似て何かを探していると思うし、使用してポイント間で長与えられた行に沿ってあるパーセンテージを指す。 Unfortuntaely私はこの関数のjavascriptポートを意識していませんが、一見価値があります。あなたのポリラインと

  • スタート(簡単のため、あなたが一連のある1つだけのパスを、持っていると仮定してみましょう:

    はまたここにあなたのニーズに合わせて、あなたに十分な詳細を与える可能性がありハックのための迅速なコンセプトです

  • 人がどこにいるかを見積もる場合は、時間に応じてパスに沿って割合を求めます(たとえば、午前8時は50%です)。
  • あなたのパス内のLatLngごとに、 LatLng間の距離を追加することで、経路の全長に沿った距離を計算できます(com puteLength、各LatLngのcomputeDistanceBetween)
  • (この場合は)50%を超えるとすぐに、このLatLngと前のLatitudeの中間にいることがわかります。望むなら正確にどれだけ距離を置いて正確に計算するか、かなり短いセグメントであればこのステップをスキップして、これらのLatLngの1つにマーカーを配置します。
  • これは一般的な概念ですが、各LatLngのパーセンテージの距離を各パスごとに1回事前に計算して別のオブジェクトに格納することで最適化し、パス内の最後のインデックスを追跡しておく必要があります次回に距離を計算するときは、最初から始めてください。

希望します。

1

このサイト:それはユーザーのドロールートをすることができますし、ルートに沿ってマイルまたはキロメートルのマーカーを追加し、それをやってしなければならないようhttp://www.gmap-pedometer.com/は、対象となり得ますあなたが必要とするものと同様の計算。

2

私は誰もが明示的に言及していない少しの細部を除いて既に答えを得ていると思います:stepsから符号化されたpolylineを使用する必要があります。それらの間の直線が経路の形状によく近似するように十分近い2つの点。

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

中央地点(全ルートで途中)に近いです最大のstepのどこかに次のようになります。トレドマドリードから

道順:

のは例を見てみましょう50km長:

{ 
    "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]@c[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" 
}, 

このポリラインは長すぎます(2856文字)〜display it directly in the Static Maps APIですが、これは必要ではありませんが、ポリラインをここに表示するのはいい方法です。とにかくInteractive Polyline Encoder Utilityを使用して、このコード化されたポリラインを(\\\に置き換えて)貼り付けて見ることができます。

ここでは、正確に20kmのこのルートのポイントを見つける必要があるとしましょう。このステップの開始から。すなわち、start_locationend_locationの間のポイントは、上記のポリラインで定義されたルートに沿ってstart_locationから20,000メートルです。

アプリでは、このポリラインをLatLng点の配列全体にデコードするために、ジオメトリライブラリのEncoding Methodsload explicitlyが必要)を使用します。隣接する2つの点の間にcomputeDistanceBetweenを使用して、start_locationから20,000を超えるポリライン内の最初のLatLng点(Y)を特定します。その後、その点と前の点(X)をとり、XYの間の直線補間を行います。この時点で、これらの2つのポイント間の直線をルートの形状の妥当な近似とみなすことができます。

これはあまりにも高価になるかもしれないかなり詳細な計算です。ポリラインのサイズが大きいためにパフォーマンスの問題が発生した場合は、ポイントの一部を削除してパフォーマンスを改善することができます。

関連する問題